在java 8之前,内部类只有在声明为final时才能访问外部对象。 但是现在当我在javaSE 1.8上运行示例代码(从下面)时,没有编译错误,程序运行正常。
为什么他们改变了这一点以及它现在如何运作?
java 7教程中的示例代码:
public class MOuter {
private int m = (int) (Math.random() * 100);
public static void main(String[] args) {
MOuter that = new MOuter();
that.go((int) (Math.random() * 100), (int) (Math.random() * 100));
}
public void go(int x, final int y){
int a = x + y;
final int b = x - y;
class MInner{
public void method(){
System.out.println("m is "+m);
System.out.println("x is "+x); // supposedly illegal - 'x' not final
System.out.println("y is: "+y);
System.out.println("a is "+a); // supposedly illegal? - 'a' not final
}
}
MInner that = new MInner();
that.method();
}
}
答案 0 :(得分:7)
在Java 7中,引入了有效最终的概念以支持"more precise rethrow" feature,并且其范围在Java 8中进行了扩展,以涵盖仅分配一次的局部变量,但不是实际声明final.
这些可以在lambda主体或内部类中捕获和使用,就像它们被声明final.
某些未声明为
final
的变量可能改为 被视为有效的最终。局部变量或方法,构造函数,lambda或异常 参数是有效的最终如果它没有被声明
final
但是它 永远不会作为赋值运算符的左手操作数出现 (§15.26)或作为前缀或后缀增量或的操作数 递减运算符(§15.14,§15.15)。此外,一个声明缺少初始化器的局部变量 如果以下所有条件都成立,则有效最终:
未声明
final.
每当它作为赋值的左操作数出现时 运营商,它绝对是未分配的,并没有明确分配 在转让之前;也就是说,它绝对是未分配的而不是 在作业的右手操作数之后明确分配 (§16 (Definite Assignment))。
它永远不会作为前缀或后缀增量的操作数或 减少运营商。
如果变量实际上是最终的,则将
final
修饰符添加到其中 声明不会引入任何编译时错误。相反,a 在有效程序中声明为final
的局部变量或参数 如果final
修饰符被删除,则变为有效最终。
答案 1 :(得分:3)
它仍然是相同的规则,除了编译器不会强迫您将变量明确定义为final
。如果它有效最终,您可以访问它。如果不是(即编译器检测到该变量被重新分配),那么它就不会编译。