昨天我接受了两个小时的技术电话面试(我通过了,woohoo!),但是我完全想出了以下有关Java动态绑定的问题。令人困惑的是,几年前我曾当过助教时曾向大学生教授这一概念,所以我给他们提供错误信息的前景有点令人不安…
这是给我的问题:
/* What is the output of the following program? */ public class Test { public boolean equals( Test other ) { System.out.println( "Inside of Test.equals" ); return false; } public static void main( String [] args ) { Object t1 = new Test(); Object t2 = new Test(); Test t3 = new Test(); Object o1 = new Object(); int count = 0; System.out.println( count++ );// prints 0 t1.equals( t2 ) ; System.out.println( count++ );// prints 1 t1.equals( t3 ); System.out.println( count++ );// prints 2 t3.equals( o1 ); System.out.println( count++ );// prints 3 t3.equals(t3); System.out.println( count++ );// prints 4 t3.equals(t2); } }
我断言输出应该是覆盖equals()方法中的两个单独的打印语句:at t1.equals(t3)和t3.equals(t3)。后一种情况足够明显,而在前一种情况下,即使t1具有Object类型的引用,也将其实例化为Test类型,因此动态绑定应调用该方法的重写形式。
equals()方
at t1.equals(t3)
t3.equals(t3)
显然不是。面试官鼓励我自己运行该程序,瞧瞧,被覆盖的方法只有一个输出:在线t3.equals(t3)。
我的问题是,为什么?正如我已经提到的,即使t1是对Object类型的引用(因此静态绑定将调用Object的equals()方法),动态绑定也应根据引用的实例化类型来调用方法的最特定版本。我想念什么?
Object
equals()
Java对重载方法使用静态绑定,对重载方法使用动态绑定。在你的示例中,equals方法被重载(与Object.equals()具有不同的参数类型),因此所调用的方法在编译时绑定到引用类型。
这里一些讨论
它是equals方法的事实并不重要,除了重载而不是覆盖它是一个常见错误之外,你已经根据面试中对问题的答案意识到了这一点。
编辑:这里也是一个很好的描述。本示例显示了与参数类型有关的类似问题,但是是由同一问题引起的。
我相信,如果绑定实际上是动态的,则在任何情况下调用方和参数均为Test实例的情况都将导致调用重写的方法。因此,t3.equals(o1)将是唯一无法打印的情况。