6

匿名クラスと最終フィールドに関する説明にはまだ満足していません。明らかな問題を説明しようとする質問がたくさんありましたが、すべての質問に対する答えが見つかりませんでした:-)

次のコードを想定します。

public void method(final int i, int j) {
    final int z = 6;
    final int x = j;
    int k = 5;
    new Runnable() {
        public void run() {
            System.out.print(i);
            System.out.print(x);
            System.out.print(z);
            System.out.print(k);
        }
    };
}
  1. 「unfinal」kプロパティのため、このコードをコンパイルすることはできません。
  2. zコンパイル時にコンパイラがプロパティを宣言された値に置き換えることができることを理解しています。

解決策を検索したところ、正確にどのように機能するかを調べたところ、i次のような回答x見つかりました。

コンパイラは、匿名クラスの lastPrice と price の使用を定数の値に置き換えるだけで (もちろんコンパイル時に)、存在しない変数にアクセスする際の問題はなくなります。

フィールドに対してどのように機能しixそれらがメソッドのパラメーターである場合はどうなりますか? それらはコンパイル時に認識されませんか? このアプローチは、z.

一方、スタックの問題に関する説明があります。

これにより、Java コンパイラは実行時に変数の値を「キャプチャ」し、コピーをフィールドとして内部クラスに格納できます。外側のメソッドが終了し、そのスタック フレームが削除されると、元の変数はなくなりますが、内側のクラスのプライベート コピーはクラス自身のメモリに残ります。

匿名クラスは、作成中に必要なすべてのコンテンツ (フィールド) を何らかの形でコピーしたことを理解しています。欠落には、匿名クラス宣言のfinalのコードが値を変更する場合、実行で可能な値が使用されるという明らかな問題があります。stale

しかし、匿名クラスのメソッドが使用されたプロパティの範囲外で実行されるとき、これは問題を解決するはずです。

ただし、このアプローチはすべてのフィールドをコピーするだけなので、宣言なしでも機能するはずです。final

どちらのアプローチも、私にとっては独立しているように見えます。そういえば - そしてそれは私の質問を解決することができます - 私はfinalメソッドフィールドがどのように機能するかを知りませんでした. メソッドが終了してもスタックから削除されませんか? 私にはナンセンスに思えますが、それは多くのことを説明します:-)

正解は?

4

3 に答える 3

8

(前述のように) メソッドから匿名クラスに変数をコピーする必要があるため、コピーされた変数が final であることを要求するのは言語設計上の決定でした。したがって、メソッドまたは匿名クラスでの代入は古い値を与えず、コードの一貫性が向上します。

しかし!Java 8 では、この要件が緩和されました。変数が事実上のfinalfinalである場合は不要になりました。変数が匿名クラスで「コピー」された後は、割り当ては許可されません。

関数表記が多いため、これは理にかなっています。そうしないと、ボタンactionPerformedを別の関数呼び出しに伝播するときに、ボタンのパラメーターが突然 final になる必要があります。

于 2013-09-19T07:27:09.220 に答える
-2

基本型を使用したため、混乱していると思います。参照について考えると、より明確になるはずです。

匿名クラスを作成すると、すべての参照が独自​​のコンテキストにコピーされます。そして、使用されるすべてのローカル変数 (およびパラメーターは単なる別の種類のローカル変数) が final でなければなりません。つまり、それは値ではなく、参照に関するものです。そして、基本型は Java の特殊なケースです (これは悲しいことです)。その場合、それらは参照のように扱われました。

これにより、この最終的な問題が明確になることを願っています。

于 2013-09-19T07:18:47.043 に答える