Java 动态绑定和方法覆盖
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/321864/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Java dynamic binding and method overriding
提问by Magsol
Yesterday I had a two-hour technical phone interview (which I passed, woohoo!), but I completely muffed up the following question regarding dynamic binding in Java. And it's doubly puzzling because I used to teach this concept to undergraduates when I was a TA a few years ago, so the prospect that I gave them misinformation is a little disturbing...
昨天我进行了两个小时的技术电话面试(我通过了,哇哦!),但我完全忽略了以下有关 Java 中动态绑定的问题。更令人费解的是,因为几年前我当助教的时候,我曾经向本科生教过这个概念,所以我给他们错误信息的前景有点令人不安……
Here's the problem I was given:
这是我得到的问题:
/* 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);
}
}
I asserted that the output should have been two separate print statements from within the overridden equals()
method: at t1.equals(t3)
and t3.equals(t3)
. The latter case is obvious enough, and with the former case, even though t1
has a reference of type Object, it is instantiated as type Test, so dynamic binding should call the overridden form of the method.
我断言输出应该是来自重写equals()
方法中的两个单独的打印语句: att1.equals(t3)
和t3.equals(t3)
. 后一种情况已经很明显了,对于前一种情况,即使t1
有一个Object类型的引用,也被实例化为Test类型,所以动态绑定应该调用方法的重写形式。
Apparently not. My interviewer encouraged me to run the program myself, and lo and behold, there was only a single output from the overridden method: at the line t3.equals(t3)
.
显然不是。我的面试官鼓励我自己运行这个程序,你瞧,被覆盖的方法只有一个输出:在t3.equals(t3)
.
My question then is, why? As I mentioned already, even though t1
is a reference of type Object (so static binding would invoke Object's equals()
method), dynamic binding shouldtake care of invoking the most specific version of the method based on the instantiated type of the reference. What am I missing?
那么我的问题是,为什么?正如我已经提到的,即使t1
是 Object 类型的引用(因此静态绑定会调用 Object 的equals()
方法),动态绑定应该负责根据引用的实例化类型调用最具体的方法版本。我错过了什么?
采纳答案by Robin
Java uses static binding for overloaded methods, and dynamic binding for overridden ones. In your example, the equals method is overloaded (has a different param type than Object.equals()), so the method called is bound to the referencetype at compile time.
Java 对重载的方法使用静态绑定,对重写的方法使用动态绑定。在您的示例中,equals 方法被重载(具有与 Object.equals() 不同的参数类型),因此调用的方法在编译时绑定到引用类型。
Some discussion here
这里有一些讨论
The fact that it is the equals method is not really relevant, other than it is a common mistake to overload instead of override it, which you are already aware of based on your answer to the problem in the interview.
它是 equals 方法的事实并不真正相关,除了重载而不是覆盖它是一个常见的错误,根据你在面试中对问题的回答,你已经意识到了这一点。
Edit: A good description hereas well. This example is showing a similar problem related to the parameter type instead, but caused by the same issue.
编辑:这里也是一个很好的描述。此示例显示了与参数类型相关的类似问题,但由相同问题引起。
I believe if the binding were actually dynamic, then any case where the caller and the parameter were an instance of Test would result in the overridden method being called. So t3.equals(o1) would be the only case that would not print.
我相信如果绑定实际上是动态的,那么调用者和参数是 Test 实例的任何情况都会导致调用覆盖的方法。所以 t3.equals(o1) 将是唯一不会打印的情况。
回答by P Arrayah
I think the key lies in the fact that the equals() method doesn't conform to standard: It takes in another Test object, not Object object and thus isn't overriding the equals() method. This means you actually have only overloaded it to do something special when it's given Test object while giving it Object object calls Object.equals(Object o). Looking that code through any IDE should show you two equals() methods for Test.
我认为关键在于 equals() 方法不符合标准:它接受另一个 Test 对象,而不是 Object 对象,因此不会覆盖 equals() 方法。这意味着您实际上只是在给定 Test 对象时重载它来做一些特殊的事情,同时给它 Object 对象调用 Object.equals(Object o)。通过任何 IDE 查看该代码应该会显示两个用于测试的 equals() 方法。
回答by Gilles
The method is overloaded instead of overriden. Equals always take an Object as parameter.
该方法被重载而不是被覆盖。Equals 总是以一个 Object 作为参数。
btw, you have an item on this in Bloch's effective java (that you should own).
顺便说一句,您在 Bloch 的有效 Java 中有一个项目(您应该拥有)。
回答by erickson
The equals
method of Test
does not override the equals
method of java.lang.Object
. Look at the parameter type! The Test
class is overloading equals
with a method that accepts a Test
.
的equals
方法Test
不会覆盖 的equals
方法java.lang.Object
。看参数类型!所述Test
类被重载equals
用一个接受的方法Test
。
If the equals
method is intended to override, it should use the @Override annotation. This would cause a compilation error to point out this common mistake.
如果该equals
方法旨在覆盖,则应使用 @Override 批注。这会导致编译错误指出这个常见错误。
回答by Uri
Java does not support co-variance in parameters, only in return types.
Java 不支持参数的协变,仅支持返回类型。
In other words, while your return type in an overriding method may be a subtype of what it was in the overridden, that is not true for parameters.
换句话说,虽然覆盖方法中的返回类型可能是它在覆盖方法中的子类型,但对于参数而言则不然。
If your parameter for equals in Object is Object, putting an equals with anything else in a subclass will be an overloaded, not an overridden method. Hence, the only situation where that method will be called is when the static type of the parameter is Test, as in the case of T3.
如果 Object 中的 equals 参数是 Object,则将 equals 与其他任何内容放在子类中将是重载方法,而不是重写方法。因此,该方法将被调用的唯一情况是当参数的静态类型为 Test 时,如 T3 的情况。
Good luck with the job interview process! I'd love to be interviewed at a company that asks these types of questions instead of the usual algo/data structures questions that I teach my students.
祝面试过程好运!我很想在一家公司接受面试,该公司会问这些类型的问题,而不是我教给学生的通常的算法/数据结构问题。
回答by Benson
Interestingly enough, in Groovy code (which could be compiled to a class file), all but one of the calls would execute the print statement. (The one comparing a Test to an Object clearly won't call the Test.equals(Test) function.) This is because groovy DOES do completely dynamic typing. This is particularly of interest because it does not have any variables that are explicitly dynamically typed. I have read in a couple of places that this is considered harmful, as programmers expect groovy to do the java thing.
有趣的是,在 Groovy 代码(可以编译为类文件)中,除了一个调用之外的所有调用都将执行打印语句。(将测试与对象进行比较的人显然不会调用 Test.equals(Test) 函数。)这是因为 groovy 做完全动态类型。这是特别有趣的,因为它没有任何显式动态类型化的变量。我在几个地方读到这被认为是有害的,因为程序员希望 groovy 来做 java 事情。
回答by Ken Gentle
See also this SO Question, closely related: Overriding the JAVA equals method quirk
另请参阅此 SO 问题,密切相关:Overriding the JAVA equals method quirk
回答by ykaganovich
The answer to the question "why?" is that's how the Java language is defined.
“为什么”这个问题的答案 这就是 Java 语言的定义方式。
To quote the Wikipedia article on Covariance and Contravariance:
Return type covariance is implemented in the Java programming language version J2SE 5.0. Parameter types have to be exactly the same (invariant) for method overriding, otherwise the method is overloaded with a parallel definition instead.
返回类型协方差在 Java 编程语言版本 J2SE 5.0 中实现。方法覆盖的参数类型必须完全相同(不变),否则该方法将被并行定义重载。
Other languages are different.
其他语言则不同。
回答by ankush gatfane
It's very clear, that there is no concept of overriding here. It is method overloading.
the Object()
method of Object class takes parameter of reference of type Object and this equal()
method takes parameter of reference of type Test.
很明显,这里没有覆盖的概念。它是方法重载。Object()
Object 类的方法采用 Object 类型的引用参数,该equal()
方法采用 Test 类型的引用参数。
回答by NguyenDat
Some note in Dynamic Binding(DD) and Static Binding???(SB) after search a while:
动态绑定(DD) 和静态绑定中的一些注意事项???(SB) 搜索一段时间后:
1.Timing execute: (Ref.1)
1.定时执行:(参考文献1)
- DB: at run time
- SB: compiler time
- DB:在运行时
- SB:编译时间
2.Used for:
2.用于:
- DB: overriding
- SB: overloading (static, private, final) (Ref.2)
- DB:覆盖
- SB:重载(静态、私有、最终)(参考文献 2)
Reference:
参考:
- Execute mean resolver which method prefer to use
- Because can not overriding method with modifier static, private or final
- http://javarevisited.blogspot.com/2012/03/what-is-static-and-dynamic-binding-in.html
- 执行均值解析器哪个方法更喜欢使用
- 因为不能用修饰符 static、private 或 final 覆盖方法
- http://javarevisited.blogspot.com/2012/03/what-is-static-and-dynamic-binding-in.html