Why do Object and var variables behave differently?
Object
has no method getSomething
. And since o1
is of type Object
the compiler won't allow you to call o1.getSomething
.
In the case of o2
the type of the variable is the anonymous inner type that you created during initialization. That type has a getSomething
method, so the compiler will allow you to call it.
Interestingly this is something that you can't directly do by having a named type. There's no type name that you use in the declaration of o2
to get the same effect, because the type is anonymous.
It is defined in JLS 14.4.1 Local Variable Declarators and Types. Specifically this part:
If LocalVariableType is var, then let T be the type of the initializer expression when treated as if it did not appear in an assignment context, and were thus a standalone expression (§15.2).
There's even an example that shows that below:
var d = new Object() {}; // d has the type of the anonymous class
The section represented as Non-Denotable Types in the JEP 286: Local-Variable Type Inference states:
Anonymous class types cannot be named, but they're easily understood—they're just classes. Allowing variables to have anonymous class types introduces a useful shorthand for declaring a singleton instance of a local class. We allow them.
Hence the method that you invoke using the var
is allowed to compile considering the class instance is created and inferred as an anonymous class further allowing the method to be invoked.
The Local Variable Declarators and Type section of the specification mentions this as a side note along with the example as well:
var d = new Object() {}; // d has the type of the anonymous class
Note that some variables declared with var cannot be declared with an explicit type, because the type of the variable is not denotable.
On the other hand, with the first instance what you're trying to perform looks like Invoking a method of an anonymous class, which fails since the type of o1
is inferred to be Object
and that further doesn't have a method called getSomething
. While if you were to invoke the method getSomething
and fix the compilation there, you could have used
Object o1 = new Object() {
String getSomething() {
System.out.println("something happened");
return "AAA";
}
}.getSomething();