【发布时间】:2020-04-04 12:53:46
【问题描述】:
有人可以解释o2 的行为吗?是因为编译器优化吗?它是否记录在 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));
}
}
产生的输出是
是的
[更新]
经过一些富有成效和有用的讨论后,我想我可以理解这种行为(如果我的假设是错误的,请发布 cmets)。
首先,感谢 @user207421,他解释说 Java 编译器将 o2 的类型视为与 RHS 相同,其中:
- 扩展
Object - 有
getSomething方法
然后感谢 @Joachim Sauer 指出了 JLS 中的正确位置。
更多相关的 JLS 引用:
局部变量的类型是 T 相对于 T 提到的所有合成类型变量的向上投影(第 4.10.5 节)。
在确定变量的类型时,向上投影应用于初始化器的类型。如果初始化器的类型包含捕获变量,则此投影将初始化器的类型映射到不包含捕获变量的超类型。
虽然允许变量的类型提及捕获变量是可能的,但通过将它们投影出来,我们强制执行一个有吸引力的不变量,即捕获变量的范围永远不会大于包含其类型被捕获的表达式的语句。非正式地,捕获变量不能“泄漏”到后续语句中。
问题:我们可以说“捕获变量”在问题的上下文中也指的是getSomething()吗?
最后,感谢 @Slaw 指出getSomething 被声明为私有包,因此getMethods 没有返回。
感谢任何 cmets/更正。
【问题讨论】:
-
这是因为
o1的类型显式声明为Object,而o2的类型与RHS相同,extendsObject并且有额外的方法,所以你可以调用它。 -
@user207421 我喜欢你的解释“RHS”,这可以更详细地显示如下:
new Object() { String getSomething() { return "AAA"; } }.getSomething();但我很想看看它在哪里被清楚地记录了。 -
您完全歪曲了我在回答中所说的话,因此它根本不符合我所说的。您对编译器实际执行的操作的误解也不正确。它所做的是将
o2的type 指定为与RHS 的type 相同,这正是var所做的。这在 JLS 中有记录。 -
@user207421 抱歉,它确实表达了我相信你并没有说的话,当我制作演示代码 sn-p 时,我的意思是概念上的,而不是字面意思。无论如何,我再次更新了问题。
-
另见this Q&A。
标签: java var type-inference java-10