Java动态绑定混淆

时间:2015-04-20 06:47:05

标签: java dynamic binding

public class Super {
     public void methodA() {
     System.out.println("super A");
     }
     public void methodC(Super arg) {
     System.out.println("C1");
     }
     public void methodC(Sub arg) {
     System.out.println("C2");
     }
     } // end class Super

 public class Sub extends Super {
 public void methodA() {
 System.out.println("sub A");
 }
 public void methodC(Super arg) {
 System.out.println("C3");
 }
 public void methodC(Sub arg) {
 System.out.println("C4");
 }
 } // end class Sub

public class BindingQuestion {
    public static void main (String[] args){
    Super one = new Super();
    Super two = new Sub();
    Sub three = new Sub();
    two.methodC(three)
    }
}

我很困惑为什么two.method(C)返回C4。不是两个宣称为超级型。这不应该意味着它只访问超级方法吗?我以为它会回归C2。至少这是我从@stvcisco在类似的先前问题中给出的答案中提出的。 Dynamic Binding Java. Does an object have the methods of its declared type, or its actual type? 我误解了他的答案吗?

5 个答案:

答案 0 :(得分:3)

调用的实例方法取决于实例的运行时类型。

Super two = new Sub();中,运行时类型为Sub(即使编译时类型为Super)。因此,two.methodC(three)会调用Sub' methodC(Sub arg)

编译时类型确定编译器可接受的可用方法签名。由于Super包含一个签名与调用two.methodC(three)匹配的方法,因此该代码可以通过编译。但是,实际调用的方法仅在运行时根据two的运行时类型确定。

答案 1 :(得分:0)

  

不是两个被宣布为超级型。

是的。

  

这不应该意味着它只访问超级方法吗?

不,这并不意味着这一点。

发生的情况如下:

在编译时,编译器会检查Super中是否存在可以处理methocC(Sub)的方法。实际上有两个。 methodC(Super)methodC(Sub)。编译器选择要在运行时绑定的最具体的签名。这个是methodC(Sub),因为SubSuper的子类。

在运行时,VM会在最具体的类中查找methodC(Sub)。这个是Sub,因为在那里定义了一个带有签名methodC(Sub)的方法,因此这个方法是绑定的。

答案 2 :(得分:0)

这是因为你覆盖了两个函数methodC(Super),methodC(Sub)Super two = new Sub(),这叫做多态。这意味着它会指向局部变量" new Sub()"以及Class Sub中的功能虽然您将其命名为Class Super。所有这些都是自动完成的。如果您在methodC(Super),methodC(Sub)中使用方法Class Super,那么methodB(Super),methodB(Sub)Class Sub。相同的操作'超级二=新的Sub(); two.methodC(三); will return "C2".In addition, the question you ask is quite common.You need to write more code to understand it.It would be better to write a project with more classes.Like超级类;类Sub1扩展超级;类Sub2; ... {{ 1}} Interface`!

答案 3 :(得分:0)

案例1)'two'是一种Super类,但它包含子类对象。因此,当您调用在超类和子类中定义的某个方法时,它会调用子类方法,因为子类已覆盖该方法。如果它没有在子类中找到那些方法,那么它将调用超类方法。

案例2)当你从super和sub类中删除方法'methodC(Sub arg)'然后它调用子类方法'methodC(Super arg)',如果没有找到则调用超类方法

  

当一个子类对象被分配给超类对象时,它会   调用第一个子类方法,因为子类覆盖超类   方法

答案 4 :(得分:0)

在理解动态和静态绑定的概念时,我认为最重要的是我们多次认为两种类型的绑定都不能在程序的范围内发生 - 这两种都是互斥的。这不是真的。它只是两个发生在程序执行的不同阶段,如果发现任何歧义,则抛出错误。例如,在您的情况下:

public class BindingQuestion {
    public static void main (String[] args){
        Super one = new Super();
        Super two = new Sub();
        Sub three = new Sub();
        two.methodC(three)
    }
}

在编译期间----------------

编译程序时,java编译器将遍历每个可执行代码。

two.methodC(three)

它将首先检查具有此签名的methodC(三)是否在SUPER类型的类中可用。为何超级?因为java中的对象是通过引用访问的。当你这样做时:

Super two = new Sub();

这意味着,对于Super类型的引用2,您指向SUB的对象。哪个好。为什么?因为在java中,除了由超类植入它们的子类之外,子类总是有一些额外的属性。因此,从上面的代码片段开始,SUB的所有属性与两个通用的属性都可以正常工作 - 它们可以通过SUPER类型的引用变量轻松访问。

因此,编译器会检查方法 在编译器通过程序执行之后没有发现任何与方法C(三个)匹配的参考类型的歧义存在于SUPER类中。

根据您提供的继承结构,有一个名为methodC的方法是SUPER类。答案是肯定的!它确实存在。现在,参数匹配吗?换句话说,签名是否匹配?答案是肯定的。因为在SUPER中公共void方法C中预期的签名( Sub arg)。你猜怎么着?三,属于SUB类型。因此编译器将通过此行而不会产生任何错误。

来运行时间

您必须记住对象并且仅在运行时调用。在编译期间检查方法和签名的类型。

现在,Java Runtime实例在调用对象2时,意识到实际上对象2是SUB类并调用SUB类中的方法。

希望这会有所帮助。