Java动态绑定和方法重写
昨天我接受了两个小时的技术电话面试(我通过了,呜呜!),但我完全忘记了以下关于Java中动态绑定的问题。这让人倍感困惑,因为几年前当我还是助教的时候,我曾经教本科生这个概念,所以我给他们错误信息的前景有点令人不安 我遇到的问题是:Java动态绑定和方法重写,java,inheritance,dynamic-binding,Java,Inheritance,Dynamic Binding,昨天我接受了两个小时的技术电话面试(我通过了,呜呜!),但我完全忘记了以下关于Java中动态绑定的问题。这让人倍感困惑,因为几年前当我还是助教的时候,我曾经教本科生这个概念,所以我给他们错误信息的前景有点令人不安 我遇到的问题是: /* What is the output of the following program? */ public class Test { public boolean equals( Test other ) { System.out.printl
/* 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()
方法中的两个单独的print语句:att1.equals(t3)
和t3.equals(t3)
。后一种情况很明显,对于前一种情况,即使t1
有一个type-Object的引用,它被实例化为type-Test,因此动态绑定应该调用方法的重写形式
显然不是。我的面试官鼓励我自己运行这个程序,你瞧,重写的方法只有一个输出:在t3.equals(t3)
行
那么我的问题是,为什么?正如我已经提到的,即使
t1
是Object类型的引用(因此静态绑定将调用Object的equals()
方法),动态绑定也应该根据引用的实例化类型调用方法的最具体版本。我缺少什么?我认为关键在于equals()方法不符合标准:它接受另一个测试对象,而不是对象对象,因此没有重写equals()方法。这意味着您实际上只重载了它,以便在给它指定测试对象的同时调用object.equals(objecto)。通过任何IDE查看代码时,都应该显示两个equals()方法进行测试。该方法是重载的,而不是重写的。Equals始终将对象作为参数
顺便说一句,你在Bloch的有效java中有一个项目(你应该拥有)。测试的
equals
方法不会覆盖java.lang.Object
的equals
方法。看看参数类型!Test
类使用接受Test
的方法重载equals
如果
equals
方法要覆盖,则应使用@override注释。这将导致一个编译错误来指出这个常见错误。Java不支持参数中的协方差,只支持返回类型中的协方差
换句话说,尽管重写方法中的返回类型可能是重写方法中的返回类型的子类型,但对于参数来说,情况并非如此
若对象中equals的参数是Object,那个么将equals与子类中的任何其他对象放在一起将是重载的,而不是重写的方法。因此,调用该方法的唯一情况是当参数的静态类型为Test时,如T3的情况
祝你面试顺利!我很想在一家公司接受面试,该公司会问这些类型的问题,而不是我教学生的常见算法/数据结构问题 有趣的是,在Groovy代码(可以编译成类文件)中,除了一个调用之外,所有调用都将执行print语句。(将测试与对象进行比较显然不会调用Test.equals(Test)函数。)这是因为groovy完全是动态类型。这尤其令人感兴趣,因为它没有任何显式动态类型的变量。我在几个地方读到过,这被认为是有害的,因为程序员希望groovy做java的事情 Java对重载方法使用静态绑定,对重写方法使用动态绑定。在您的示例中,equals方法重载(与Object.equals()具有不同的param类型),因此调用的方法在编译时绑定到引用类型 一些讨论 事实上,它是equals方法并不是真正相关的,只是过载而不是覆盖它是一个常见的错误,根据你在面试中对问题的回答,你已经意识到了这一点 编辑: 这也是一个很好的描述。本例显示了与参数类型相关的类似问题,但由同一问题引起
我相信,如果绑定实际上是动态的,那么调用方和参数是Test实例的任何情况都会导致调用重写的方法。因此t3.equals(o1)将是唯一不会打印的情况。问题“为什么?”的答案是Java语言就是这样定义的 引述: 实现了返回型协方差 在Java编程语言中 J2SE5.0版。参数类型具有 完全相同(不变) 方法重写,否则 方法使用并行函数重载 而是定义
其他语言是不同的。很明显,这里没有覆盖的概念。这是方法重载。
对象类的
Object()
方法采用类型对象的引用参数,此equal()
方法采用类型测试的引用参数。动态绑定(DD)和静态绑定̣̣(SB)搜索一段时间后注意:
1.定时执行:(参考1)
- DB:在运行时
- SB:编译时间
- DB:覆盖
- SB:过载(静态、专用、最终)(参考2)
我发现了一篇关于动态绑定和静态绑定的有趣文章。它附带了一段模拟dy的代码
public class DynamicBinding {
public boolean equals(Test other) {
System.out.println("Inside of Test.equals");
return false;
}
@Override
public boolean equals(Object other) {
System.out.println("Inside @override: this is dynamic binding");
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);
}
}
public class Test {
public boolean equals(Test other) {
System.out.println("Inside of Test.equals");
return false;
}
@Override
public boolean equals(Object other) {
System.out.println("Inside of Test.equals ot type Object");
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
o1.equals(t2);
System.out.println("\n" + count++); // prints 1
o1.equals(t3);
System.out.println("\n" + count++);// prints 2
t1.equals(t2);
System.out.println("\n" + count++);// prints 3
t1.equals(t3);
System.out.println("\n" + count++);// prints 4
t3.equals(o1);
System.out.println("\n" + count++);// prints 5
t3.equals(t3);
System.out.println("\n" + count++);// prints 6
t3.equals(t2);
}
}