17

メソッド内で定義された内部クラスは、これらのローカル変数がマークされていない限り、メソッドのローカル変数にアクセスできませんfinal。スタックオーバーフローとJavaコードランチの他の投稿を見ましたが、どのようにマークするかについての質問に正確に答えているものはないようです。変数finalを使用すると、内部クラスはメソッド内のローカル変数にアクセスできます。

class MyOuter {
    private String x = "Outer";

    void fly(final int speed) {
        final int e = 1;
        class FlyingEquation {

            public void seeOuter()
            {
                System.out.println("Outer x is " + x);
            }
            public void display()
            {
                System.out.println(e);// line 1
                System.out.println(speed);// line 2
            }
        }
        FlyingEquation f=new FlyingEquation();
        f.seeOuter();
        f.display();
    }       
    public static void main(String args[])
    {
        MyOuter mo=new MyOuter();
        mo.fly(5);
    }
}

私がこれに見つけた説明:

ローカル変数はスタックに格納され、メソッド呼び出しが終了するとすぐにスタックがポップアップされ、ローカル変数にアクセスできなく なりますが、最終的なローカル変数はメモリのデータセクションに格納されJVM、メソッド呼び出しの終了後もアクセスできる可能性があります。どこにありdata section of memoryますか?最終的なローカル変数はすべてスタックに格納されていると思います。メソッドがスタックから削除されると、最終的な変数も一緒に削除されます。最終変数の値は、オブジェクトとともにヒープに格納されますか?

メソッドまたはクラスのいずれかによって変更される可能性があるため、非最終フィールドはサポートされません。実際には2つの異なるフィールド/変数があるため、これはサポートされません。

4

6 に答える 6

13

ローカル変数をとしてマークするfinalと、割り当てられた後はその値が変更されないことが保証されていることをコンパイラーに通知します。これにより、コンパイラは内部クラス内に合成フィールドを作成し、内部クラスインスタンスの構築時にローカル変数の値をこの合成フィールドにコピーすることが安全になります。内部クラスコード内からのローカル変数のすべての読み取りは、実際には代わりに合成フィールドの読み取りにコンパイルされます。

このトリックは、内部クラスがインスタンス化された後に変更される可能性があり、合成フィールドが元の変数と同期しなくなる可能性があるため、非最終変数では機能しません。

すべての内部クラスはコンパイラのトリックであることを理解することが重要です。ランタイムJVMでは、すべてのクラス(トップレベル、ネストされた静的、および内部)は同じように扱われます。

于 2012-10-23T08:08:33.993 に答える
12

内部クラスのインスタンス化中に、メソッドとクラスの両方がスコープ内にある場合、内部クラスは定数である変数のコピーを作成します。これは、内部クラスが使用しているのはメソッドのみであるため、メソッドがスコープ外になる可能性があることを意味します。変数のコピー。 この記事をチェックしてください

于 2012-10-23T08:14:45.283 に答える
2

はい、最終的なローカル変数はスタックに保存され、メソッドがスタックから削除されるとすぐに破棄されます。@Ianが提案したように、コンパイラが変数のfinalキーワードを確認すると、ヒープ上の内部クラスオブジェクトに値のコピーが作成されます。

于 2012-10-23T08:20:07.950 に答える
0

この背後にある話は、Javaの作成者がクロージャを完全にサポートするのに十分な時間がなかったということです。

言語サポートを閉鎖する方法はいくつかあります。たとえば、スキームでは、関数の自由パラメーターは、関数が定義されている字句スコープに対応する環境にバインドされます。SMLなどの不変データを強制する言語では、クロージャに必要なローカル変数をヒープにコピーすることで、クロージャを実装できます。

したがって、彼らは、MLのスタイルを模倣する貧乏人バージョンのクロージャを持つ内部クラスを作成します。

于 2014-03-25T15:29:52.660 に答える
0

メソッドローカル内部クラスは、そのローカル変数がfinalとして宣言されない限り、外部メソッドのローカル変数を使用できません。ローカル変数をfinalとして宣言する必要がある主な理由は、ローカル変数はメソッドがスタックに存在するまでスタックに存在しますが、内部クラスのオブジェクトがまだヒープに存在する場合があるためです。

この記事をチェックアウトしてください:http: //www.geeksforgeeks.org/inner-class-java/

于 2015-04-08T12:31:04.467 に答える
0

それでは、考えてみましょう。メソッドのローカル変数はスタック上に存在し、メソッドの存続期間中のみ存在します。ローカル変数のスコープは、変数が宣言されているメソッドに限定されることはすでにわかっています。メソッドが終了すると、スタックフレームが吹き飛ばされ、変数は履歴になります。ただし、メソッドが完了した後でも、メソッド内で作成された内部クラスオブジェクトは、たとえば、その参照が他のコードに渡されてインスタンス変数に格納された場合、ヒープ上で存続している可能性があります。ローカル内部クラスオブジェクトがメソッドローカル内部クラスオブジェクトである限り、ローカル変数が有効であることが保証されていないため、内部クラスオブジェクトはそれらを使用できません。ローカル変数がfinalとマークされていない限り。

最終的なローカル変数はスタックではなくヒープに格納されますか?

説明: SOで調査した結果、すべてのローカル変数(finalまたはnot )がスタックに格納され、メソッドの実行が終了するとスコープから外れることがわかりました。

ただし、final変数についてJVMは、開始後に変更されないため、これらを定数と見なします。そして、内部クラスがそれらにアクセスしようとすると、コンパイラはその変数のコピー(それ自体ではない)をヒープ に作成し、内部クラス内に合成フィールドを作成します。したがって、メソッドの実行が終了しても、内部クラスがアクセスできるため、内部クラスにアクセスできます。クラスには独自のコピーがあります。合成分野ソースコードには実際には存在しないファイルが提出されますが、コンパイラはこれらのフィールドをアクセス可能にするために、いくつかの内部クラスでそれらのフィールドを作成します。簡単な言葉で隠しフィールド。

したがって、final変数もスタックに格納されますが、内部クラスがヒープに格納した変数をコピーします。

于 2016-02-29T19:31:40.110 に答える