Can someone explain the behavior of o2
? Is it due to compiler optimization? Is it documented somewhere in the JLS?
public class Test {
public static void main(String[] args) {
Object o1 = new Object() {
String getSomething() {
return "AAA";
}
};
// o1.getSomething(); // FAILS
String methods1 = Arrays.toString(o1.getClass().getMethods());
var o2 = new Object() {
String getSomething() {
return "AAA";
}
};
o2.getSomething(); // OK
String methods2 = Arrays.toString(o2.getClass().getMethods());
System.out.println(methods1.equals(methods2));
}
}
The output produced is
true
[UPDATE]
After some productive and useful discussion I think I can understand the behavior (please post comments if my assumption is wrong).
First off, thanks to @user207421 who explained that the Java compiler treats the type of o2
the same as the RHS, which:
- extends
Object
- has the
getSomething
method
Then thanks to @Joachim Sauer who pointed to the proper place in the JLS.
Some more related JLS quotes:
The type of the local variable is the upward projection of T with respect to all synthetic type variables mentioned by T (§4.10.5).
Upward projection is applied to the type of the initializer when determining the type of the variable. If the type of the initializer contains capture variables, this projection maps the type of the initializer to a supertype that does not contain capture variables.
While it would be possible to allow the type of the variable to mention capture variables, by projecting them away we enforce an attractive invariant that the scope of a capture variable is never larger than the statement containing the expression whose type is captured. Informally, capture variables cannot "leak" into subsequent statements.
Question: can we say that "capture variables" refers to getSomething()
too in the context of the question?
And finally, thanks to @Slaw for pointing out that getSomething
was declared package private so was not returned by getMethods
.
Any comments/corrections appreciated.
o1
is explicitly declared asObject
while the type ofo2
is the same as the RHS, which extendsObject
and has the extra method, so you can call it. – Saegernew Object() { String getSomething() { return "AAA"; } }.getSomething();
But I would love to see where is it clearly documented. – Meggso2
to be the same as the type of the RHS, that being exactly whatvar
does. Which is documented in the JLS. – Saeger