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

时间:2014-04-12 21:34:49

标签: java interface polymorphism

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

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

2 个答案:

答案 0 :(得分:3)

通过阅读此代码,您无法知道。

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

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

其余的是细节,你不必担心。

当然,在调试时,这是一个不同的故事:你想知道哪个实现被执行,因为它可能是错误的。在这种情况下,只需按照调试器查看实际执行的代码,否则,您不应该关心,这就是多态性的所有内容:获取抽象。

答案 1 :(得分:0)

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

在编译语言中,编译器将源代码转换为机器指令。当它将方法转换为机器代码时,该方法在内存中接收该方法开始的地址。当另一段代码调用该方法时,内存地址写在客户端代码的代码中。该内存地址是固定的,因此该段代码不能在运行时调用任何其他方法。它总是会调用一个方法,而不是一个不同的方法。

例如说我们有类似的东西:

private int someMethod() { ... }

编译器说someMethod位于003.所以当它编译这样的代码时:

public myMethod() {
    this.someMethod();
}

它说myMethod调用someMethod,并在内存中查找someMethod所在的位置。大致它会写出类似的东西:

// myMethod
call 003

现在,方法调用(也就是调用站点)只能永远调用someMethod。它永远不会调用任何其他方法,但确切的方法。

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

// myMethod
methodAddress = this.methodsAddresses['someMethod']
call methodAddress

这是查找(有时称为虚拟指针表),它允许方法根据someObject指向的内容进行更改,并且该查找允许它在运行时发生变化。

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