在方法中声明类 – 最终关键字

给定方法中的以下内部类(IsSomething):

public class InnerMethod { private int x; public class Something { private int y; public void printMyNumber(double x) { class IsSomething extends Something { public void print() { System.out.println(x); } } } } } 

为什么X变量必须是FINAL才能使它工作..? (我说的是关于“printMyNumber”函数的X参数。)

区别在于局部变量与类成员变量之间。 成员变量在封闭对象的生命周期中存在,因此它可以由内部类实例引用。 但是,局部变量仅在方法调用期间存在,并且由编译器以不同方式处理,因为它的隐式副本是作为内部类的成员生成的。 在不声明局部变量fi​​nal的情况下,可以更改它,导致由于内部类仍然引用该变量的原始值而导致的细微错误。

最终的局部变量

我知道创建局部变量或参数最终的原因有两个。 第一个原因是您不希望代码更改局部变量或参数。 许多人认为改变方法内部的参数是不好的风格,因为它使代码不清楚。 作为一种习惯,一些程序员将所有参数设置为“最终”以防止他们自己更改它们。 我不这样做,因为我发现它使我的方法签名有点难看。

当我们想要从内部类中访问局部变量或参数时,第二个原因就出现了。 据我所知,这是实际的原因,最终的局部变量和参数被引入到JDK 1.1中的Java语言中。

 public class Access1 { public void f() { final int i = 3; Runnable runnable = new Runnable() { public void run() { System.out.println(i); } }; } } 

在run()方法中,如果我们在外部类中使它成为最终的,我们只能访问i。 为了理解推理,我们必须这样做

看看编译器的作用。 它生成两个文件,Access1.class和Access1 $ 1.class。 当我们用JAD反编译它们时,我们得到:

 public class Access1 { public Access1() {} public void f() { Access1$1 access1$1 = new Access1$1(this); } } 

 class Access1$1 implements Runnable { Access1$1(Access1 access1) { this$0 = access1; } public void run() { System.out.println(3); } private final Access1 this$0; } 

由于i的值是final,编译器可以将其“内联”到内部

类。 令我感到不安的是,在看到上述内容之前,局部变量必须是内部类才能访问的最终变量。

当局部变量的值可以针对内部类的不同实例而改变时,编译器将其添加为内部类的数据成员,并允许它在构造函数中初始化。 这背后的根本原因是Java没有指针,就像C一样。

考虑以下课程:

 public class Access2 { public void f() { for (int i=0; i<10; i++) { final int value = i; Runnable runnable = new Runnable() { public void run() { System.out.println(value); } }; } } } 

这里的问题是我们每次进行for循环时都必须创建一个新的本地数据成员,这是我今天的想法

编码时,是将上面的代码更改为以下代码:

 public class Access3 { public void f() { Runnable[] runners = new Runnable[10]; for (final int[] i={0}; i[0] 

我们现在不必声明一个额外的最终局部变量。 事实上,这可能不是真的

int []我就像一个指向int的常见C指针? 我花了4年才看到这个,但是如果你在其他地方听过这个想法,我想听听你的意见。

匿名类中的方法实际上无法访问局部变量和方法参数。 相反,当实例化匿名类的对象时,对象方法引用的最终局部变量和方法参数的副本将作为实例变量存储在对象中。 匿名类的对象中的方法确实访问那些隐藏的实例变量。

来自JLS:

Any local variable, formal method parameter or exception handler parameter used but not declared in an inner class must be declared final. Any local variable, used but not declared in an inner class must be definitely assigned (§16) before the body of the inner class.

这是因为本地类实例的生命周期可能比定义类的方法的执行时间长得多。 因此,本地类必须具有它使用的所有局部变量的私有内部副本(这些副本由编译器自动生成)。 确保局部变量和私有副本始终相同的唯一方法是坚持局部变量是最终的。