Java dynamic binding and method overriding

2019-01-02 21:54发布

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...

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.

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).

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 should take care of invoking the most specific version of the method based on the instantiated type of the reference. What am I missing?

13条回答
别忘想泡老子
2楼-- · 2019-01-02 22:38

The answer to the question "why?" is that's how the Java language is defined.

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.

Other languages are different.

查看更多
乱世女痞
3楼-- · 2019-01-02 22:43

Java does not support co-variance in parameters, only in return types.

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.

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.

查看更多
孤傲高冷的网名
4楼-- · 2019-01-02 22:43

Some note in Dynamic Binding (DD) and Static Binding̣̣̣(SB) after search a while:

1.Timing execute: (Ref.1)

  • DB: at run time
  • SB: compiler time

2.Used for:

  • DB: overriding
  • SB: overloading (static, private, final) (Ref.2)

Reference:

  1. Execute mean resolver which method prefer to use
  2. Because can not overriding method with modifier static, private or final
  3. http://javarevisited.blogspot.com/2012/03/what-is-static-and-dynamic-binding-in.html
查看更多
Evening l夕情丶
5楼-- · 2019-01-02 22:43

I found an interesting article about dynamic vs. static binding. It comes with a piece of code for simulating dynamic binding. It made my code a more readable.

https://sites.google.com/site/jeffhartkopf/covariance

查看更多
看我几分像从前
6楼-- · 2019-01-02 22:45

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.

查看更多
仙女界的扛把子
7楼-- · 2019-01-02 22:45

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.

查看更多
登录 后发表回答