Search code examples
javavarjava-10

Java 10 'var' and inheritance


Following a review of the var feature as seen here:

I have encountered difficulties with setting up my Eclipse/IntelliJ IDEA IDEs with JDK 10 and am therefore asking help from Stack Overflow users who have a working Java 10 environment.

Consider the following:

public class A {
   public void someMethod() { ... }
}
public class B extends A{
   @Override
   public void someMethod() { ... }
}
...
...
...
var myA = new A(); // Works as expected
myA = new B(); // Expected to fail in compilation due to var being
               // syntactic sugar for declaring an A type
myA = (A) (new B()); // Should work
myA.someMethod(); // The question - which someMethod implementation is called?

When using var, I expect the JVM to recognize the deriving class type which the variable holds. And to execute B:someMethod() instead of A:someMethod() when executing myA.someMethod().

Is this indeed the case?


Solution

  • Thanks to nullpointer providing a link to an online Java 10 compiler, I got the following interesting results:

    public class Main {
        static class A {
               public void someMethod() { System.out.println(this.getClass().getName()); }
        }
        static class B extends A{
               @Override
               public void someMethod() { System.out.println("Derived: " + this.getClass().getName()); }
        }
        public static void main(String[] args) {
            var myA = new A();
            myA.someMethod();
            myA = new B(); // does not fail to compile!
            myA.someMethod();
        }
    }
    

    And the outputs:

    Main$A // As expected
    Derived: Main$B  // As expected in inheritance
    

    Conclusion - var is syntactic sugar: var myA = new A() is equivalent to A myA = new A(), with all the OOP associated with it.

    PS: I tried to play a little with a var holding an anonymous class and came up with this interesting behavior - thanks (yet again) to nullpointer for mentioning it as a duplicate of why can't we assign two inferred variables as an anonymous class to each other:

    static interface Inter {
        public void method();
    }
    
    public static void main(String[] args) {
        var inter = new Inter() {
            @Override
            public void method() {System.out.println("popo");}
        };
        inter.method();
        inter = new Inter() {
            @Override
            public void method() {System.out.println("koko");}
        };
        inter.method();
    }
    

    And the output:

    Main.java:11: error: incompatible types: <anonymous Inter> cannot be converted to <anonymous Inter>
            inter = new Inter() {
                    ^
    

    The second assignment to var fails due to the second anonymous class type differing from the first anonymous class type - enforcing the syntactic sugar role of the var keyword.

    It is surprising that the error message is not more refined - currently it makes little sense since the type names displayed in the error are identical!