匿名类可以访问java 8中的非最终外部对象吗?

时间:2014-10-27 20:06:13

标签: java java-8

在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();
    }   
}

2 个答案:

答案 0 :(得分:7)

在Java 7中,引入了有效最终的概念以支持"more precise rethrow" feature,并且其范围在Java 8中进行了扩展,以涵盖仅分配一次的局部变量,但不是实际声明final.这些可以在lambda主体或内部类中捕获和使用,就像它们被声明final.

一样

section §4.12.4

Java Language Specification涵盖了这一点
  

某些未声明为final的变量可能改为   被视为有效的最终

     

局部变量或方法,构造函数,lambda或异常   参数是有效的最终如果它没有被声明final但是它   永远不会作为赋值运算符的左手操作数出现   (§15.26)或作为前缀或后缀增量或的操作数   递减运算符(§15.14§15.15)。

     

此外,一个声明缺少初始化器的局部变量   如果以下所有条件都成立,则有效最终

     
      
  • 未声明final.

  •   
  • 每当它作为赋值的左操作数出现时   运营商,它绝对是未分配的,并没有明确分配   在转让之前;也就是说,它绝对是未分配的而不是   在作业的右手操作数之后明确分配   (§16 (Definite Assignment))。

  •   
  • 它永远不会作为前缀或后缀增量的操作数或   减少运营商。

  •   
     

如果变量实际上是最终的,则将final修饰符添加到其中   声明不会引入任何编译时错误。相反,a   在有效程序中声明为final的局部变量或参数   如果final修饰符被删除,则变为有效最终。

答案 1 :(得分:3)

它仍然是相同的规则,除了编译器不会强迫您将变量明确定义为final。如果它有效最终,您可以访问它。如果不是(即编译器检测到该变量被重新分配),那么它就不会编译。