区别在于局部变量和类成员变量。成员变量存在于封闭对象的生命周期中,因此它可以被内部类实例引用。然而,局部变量仅在方法调用期间存在,并且编译器以不同的方式处理,因为它的隐式副本作为内部类的成员生成。如果不将局部变量声明为 final,则可能会对其进行更改,从而导致细微的错误,因为内部类仍然引用该变量的原始值。
Final local variables
我知道创建一个局部变量或一个
参数最终。第一个原因是你不想要你的代码
改变局部变量或参数。许多人认为
更改方法内的参数是不好的风格,因为它使
代码不清楚。作为一种习惯,一些程序员使他们的所有参数
“final”以防止自己改变它们。我不这样做,
因为我发现它让我的方法签名有点难看。
第二个原因是当我们想要访问一个局部变量或
内部类中的参数。这是真正的原因,因为
据我所知,最终的局部变量和参数是
在 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 设为 final 时,我们才能访问它。为了理解推理,我们必须
看看编译器做了什么。它产生两个文件,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 的值是最终的,编译器可以将其“内联”到内部
类。局部变量必须是最终的,这让我感到不安
由内部类访问,直到我看到上面的内容。
当局部变量的值可以根据不同的情况改变时
内部类的实例,编译器将其添加为
内部类并让它在构造函数中初始化。这
这背后的根本原因是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]<runners.length; i[0]++) {
runners[i[0]] = new Runnable() {
private int counter = i[0];
public void run() {
System.out.println(counter);
}
};
}
for (int i=0; i<runners.length; i++)
runners[i].run();
}
public static void main(String[] args) {
new Access3().f();
}
}
我们现在不必声明额外的最终局部变量。事实上,这也许不是真的
int[] i 就像一个指向 int 的通用 C 指针?我花了4年时间
看到这个,但如果你听说过这个想法,我想听听你的意见
其他地方。