Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/304.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 将调用接口实现的哪个对象方法_Java_Interface_Polymorphism - Fatal编程技术网

Java 将调用接口实现的哪个对象方法

Java 将调用接口实现的哪个对象方法,java,interface,polymorphism,Java,Interface,Polymorphism,我有一个类似下面的项目代码。这里,通过使用接口强制转换,我们将调用服务IAAuthenticateService的方法authenticate()。现在有5个子类具有相同的方法实现和实现相同的接口IAuthenticateService。通过查看代码,我将如何知道调用了哪个类方法实现?我对界面设计有点困惑 ((IAuthenticateService) AuthServiceApp.getInstance().getContext() .getServic

我有一个类似下面的项目代码。这里,通过使用接口强制转换,我们将调用服务IAAuthenticateService的方法authenticate()。现在有5个子类具有相同的方法实现和实现相同的接口IAuthenticateService。通过查看代码,我将如何知道调用了哪个类方法实现?我对界面设计有点困惑

((IAuthenticateService) AuthServiceApp.getInstance().getContext()
                    .getService(ServiceEnum.CredentialService.name()))
                    .authenticate(inputParams);

你不能仅仅通过阅读这些代码就知道

但是,程序将在运行时知道调用哪个实现:由
AuthServiceApp.getInstance().getContext()
返回的对象将具有一个类型,哪个类型将具有方法
getService
的单个实现,并且将调用此实现

作为一名程序员,你不需要知道更多。该范例允许您不必担心将调用哪个实现。您需要知道的是,给定一个特定的环境,您将获得一个上下文实例,您可以在该实例上调用
getService()
,它将为您提供一个服务

剩下的都是细节,你不用担心


当然,当您进行调试时,情况就不同了:您想知道执行哪个实现,因为它可能有缺陷。在这种情况下,只需跟随调试器查看真正执行了哪些代码,否则,您不应该在意,这就是多态性的全部含义:获得抽象。

那么,您无法知道返回的是IAAuthentication的什么实现,这就是接口的全部意义。我们使用接口将代码的各个部分彼此分开。这使得程序更具可扩展性和通用性,从而推动代码重用。它是一个非常强大的概念,是现代软件开发的基石。客户端(使用接口方法的代码)不关心接口的另一端(即接口的实现者)是什么。这允许客户端在运行时进行更改。你不知道的事实是什么赋予了它力量。为了理解这个概念,您必须考虑编译器是如何工作的,以及它在编译代码时做了什么

在编译语言中,编译器将源代码翻译成机器指令。当它将一个方法翻译成机器代码时,该方法在内存中接收该方法开始的地址。当另一段代码调用该方法时,内存地址将写入客户机代码的代码中。内存地址是固定的,这样代码就不能在运行时调用任何其他方法。它总是调用一个方法,而不是另一个方法

例如,假设我们有这样的东西:

private int someMethod() { ... }
public myMethod() {
    this.someMethod();
}
// myMethod
methodAddress = this.methodsAddresses['someMethod']
call methodAddress
编译器说someMethod位于003。因此,当它编译这样的代码时:

private int someMethod() { ... }
public myMethod() {
    this.someMethod();
}
// myMethod
methodAddress = this.methodsAddresses['someMethod']
call methodAddress
它说myMethod调用someMethod,并查找someMethod在内存中的位置。大致上,它会写出如下内容:

// myMethod
call 003
现在,方法调用(也称为调用站点)只能永远调用someMethod。它不会调用任何其他方法,只会调用该确切方法

但在OO语言中,我们可以改变在运行时调用哪个实际方法。这意味着编译器在编译类时无法将该内存地址写入调用方代码。相反,它必须在运行时查找该方法地址。它如何做到这一点是通过在运行时传递的对象中按名称查找方法。因此,编译器可能会执行以下操作:

private int someMethod() { ... }
public myMethod() {
    this.someMethod();
}
// myMethod
methodAddress = this.methodsAddresses['someMethod']
call methodAddress
正是这种查找(有时称为虚拟指针表)使方法能够根据someObject指向的对象而改变,并且这种查找允许它在运行时改变


在您需要调试某些东西之前,这一切都很好。如果您试图调试某些东西,那么使用调试器并在客户机代码中删除断点是最简单的,您可以很容易地在进入代码的同时查看许多其他内容。您也可以打印someObject.getClass().getName()来查找名称,但如果您正在调试,这只是一个开始。

您不需要知道,只需遵循合同,您对他们的工作感兴趣,而不是对他们的工作方式感兴趣。顺便说一句,您只能在运行时执行时才知道。@Snicolus-非常感谢您的解释。正如您所说的,getService()方法只有一个实现,它是由抽象类IMapService定义的。现在有3个IMapService类的基类,每个基类都实现authenticate()方法。编译器如何在运行时调用正确的实现?当然,使用调试器,我能够找到正确的类调用实现方法。这与正确性无关。给出了具体的实现方法。对不起,不太清楚。调试你的程序并一步一步地进行,你会发现的。@snicolas-使用调试器,我能够找到实际的方法调用。我不清楚的是jvm在运行时如何调用实现该方法的类。很抱歉,我之前的评论没有完成。我想,你的整个谜团在于getInstance()或getService()。尝试查看这些方法体,您将看到从一个实现切换到另一个实现的标准是什么。