32

内部クラスのインスタンスがある場合、内部クラスにないコードから外部クラスにアクセスするにはどうすればよいですか? 内部クラス内でOuter.this、外部クラスを取得するために使用できることはわかっていますが、これを取得する外部の方法が見つかりません。

例えば:

public class Outer {
  public static void foo(Inner inner) {
    //Question: How could I write the following line without
    //  having to create the getOuter() method?
    System.out.println("The outer class is: " + inner.getOuter());
  }
  public class Inner {
    public Outer getOuter() { return Outer.this; }
  }
}
4

8 に答える 8

33

クラスのバイトコードには、typeOuter$Innerという名前のパッケージスコープのフィールドが含まれます。バイトコード レベルでは内部クラスの概念がないため、これが非静的内部クラスの Java での実装方法です。this$0Outer

本当に必要な場合は、リフレクションを使用してそのフィールドを読み取ることができるはずです。私はそれをする必要がなかったので、必要がないようにデザインを変更するのが最善です.

リフレクションを使用する場合のサンプル コードは次のようになります。男、それは醜いです。;)

public class Outer {
    public static void foo(Inner inner) {
        try {
            Field this$0 = inner.getClass().getDeclaredField("this$0");
            Outer outer = (Outer) this$0.get(inner);
            System.out.println("The outer class is: " + outer);

        } catch (NoSuchFieldException e) {
            throw new RuntimeException(e);
        } catch (IllegalAccessException e) {
            throw new RuntimeException(e);
        }
    }

    public class Inner {
    }

    public void callFoo() {
        // The constructor of Inner must be called in 
        // non-static context, inside Outer.
        foo(new Inner()); 
    }

    public static void main(String[] args) {
        new Outer().callFoo();
    }
}
于 2009-04-18T15:32:29.773 に答える
14

設計上、方法はありません。内部クラスのインスタンスを介して外部クラスにアクセスする必要がある場合、設計は逆になります。内部クラスのポイントは、通常、外部クラス内でのみ、またはインターフェイスを介して使用されます。

于 2009-04-18T14:52:20.307 に答える
8

外部クラスにアクセスする必要があるときにゲッターを追加することの何が問題になっていますか?そうすれば、アクセスを許可するかどうかを制御できます。

于 2009-04-18T15:41:55.430 に答える
6

実際、これは非常に良い質問です。たとえば、クラスの 2 つの異なるインスタンスがInnnerクラスの同じインスタンスを共有しているかどうかを確認できるようにする必要がある場合Outer(コンテキストに応じて == または等しい)。

汎用インターフェイスを作成することをお勧めします(名前付き内部クラスには絶対に必要ではありませんが、「インスタンス化」/キャストできます):

public interface InnerClass<Outer> {
    Outer getOuter();
}

これは、任意の名前付き内部クラスに適用できます。

次に、次のようなことを行います。

class MyInnerClass implements InnerClass<Outer> {
    Outer getOuter() {
        return Outer.this;
    }
    // remaining implementation details
}

このようにして、インターフェイスを実装する内部クラスから外部クラスにアクセスできInnerClass<Outer>ます(実際に実装されていることを確認します)。

内部クラスが匿名の場合は、次のことしかできません (サンプルを提供してくれた Rich MacDonald に感謝します)。

new InterfaceOrAbstractClass<Outer>() {
    Outer getOuter() { // super inefficient but this is the only way !
        return (Outer)getClass().getDeclaredField("this$0");
    }
    /* other methods */
}

ただし、匿名クラス本体の外部にアクセスできるように実装するInterfaceOrAbstractClass 必要があります!InnerClass<Outer>getOuter()

javac がすべての内部クラスにある種のInnerClass<Outer>インターフェースを自動的に実装すると、非常に簡単になり、匿名クラスでも非常に効率的に実行できます (遅いイントロスペクション処理はありません)!

于 2012-07-14T10:48:06.987 に答える
1

(非静的)内部クラスがある場合は、定義上、外部クラスの囲んでいるコンテキスト内でのみ機能するものを操作していることになります。したがって、内部クラスへのハンドルを取得するには、外部インスタンスを介してそれを取得している必要があります。したがって、そのようなアクセサが必要になるポイントに到達するために私が見ることができる唯一の方法は、外部参照を介して内部を取得し、外部インスタンス参照を失うか破棄することです。

例えば:

public class Outer{ 
   public class Inner {
   }
}

public class UsesInner{
 Collection<Outer.Inner> c = new ArrayList<Outer.Inner>();
}

現在、cにデータを入力する唯一の方法は、Outer()インスタンスを作成することです。私はこのような何かのための有用な目的を見たいと思います。

于 2009-04-18T15:53:29.693 に答える
1

これを書くだけで

class Outer {
  class Inner {
    Outer outer = Outer.this;
  }
}
于 2013-01-29T17:22:47.857 に答える
1

この動作が必要な理由の 1 つを次に示します。内部インスタンスがあり、リフレクションを使用classして外部で定義されたメソッドにアクセスする必要がある場合。class

記録のために、inner.getClass().getDeclaredField("this$0")動作します。フィールドがprivateであるため、 も呼び出す必要がありますfield.setAccessible(true)

于 2009-11-03T21:58:08.940 に答える
0

あなたはこのようなことをすることはできません:

public static class Inner { // static now
    private final Outer parent;

    public Inner(Outer parent) { this.parent = parent; }

    public Outer get Outer() { return parent; }
}
于 2009-04-18T15:46:23.533 に答える