違いは、ローカル変数とクラス メンバー変数の違いです。メンバー変数は、囲んでいるオブジェクトの存続期間中に存在するため、内部クラスのインスタンスから参照できます。ただし、ローカル変数はメソッドの呼び出し中にのみ存在し、その暗黙的なコピーが内部クラスのメンバーとして生成されるという点で、コンパイラによって異なる方法で処理されます。ローカル変数 final を宣言しないと、それを変更でき、内部クラスが依然としてその変数の元の値を参照しているため、微妙なエラーが発生する可能性があります。
最終ローカル変数
ローカル変数またはパラメーターを final にする理由は 2 つあります。最初の理由は、コードでローカル変数またはパラメーターを変更したくないからです。コードが不明確になるため、メソッド内のパラメーターを変更するのは悪いスタイルであると多くの人が考えています。一部のプログラマーは、習慣として、すべてのパラメーターを「最終」にして、自分でパラメーターを変更できないようにしています。メソッドの署名が少し見苦しくなるので、私はそうしません。
2 つ目の理由は、内部クラス内からローカル変数またはパラメーターにアクセスする場合です。これが、私の知る限り、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() メソッド内では、外部クラスで final にした場合にのみ i にアクセスできます。その理由を理解するには、
コンパイラが何をするか見てください。Access1.class と Access1$1.class の 2 つのファイルが生成されます。それらを 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]<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();
}
}
追加の final ローカル変数を宣言する必要がなくなりました。実際、それはおそらく真実ではないでしょうか?
int[] i は int への一般的な C ポインターのようなものですか? これを見るのに4年かかりましたが、このアイデアをどこかで聞いたことがあるなら、あなたから聞いてみたい.