web-dev-qa-db-ja.com

Javaでは、内部クラスにいない場合、外部クラスにどのようにアクセスしますか?

内部クラスのインスタンスがある場合、外部クラスにアクセスするにはどうすればよいですか 内部クラスにないコードから?私は内部クラス内で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; }
  }
}
32
Kip

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

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

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

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();
    }
}
32
Esko Luontola

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

14

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

8
starblue

これは、たとえば、Innnerクラスの2つの異なるインスタンスがOuterクラス(==またはコンテキストに応じて等しい)。

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

_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 */
}
_

しかしInterfaceOrAbstractClassmustは_InnerClass<Outer>_を実装して、匿名クラス本体の外部でgetOuter()にアクセスできるようにします!

Javacがすべての内部クラスに何らかの_InnerClass<Outer>_インターフェースを自動的に実装し、匿名クラス(イントロスペクション処理が遅くならない)でも非常に効率的に実行できれば、はるかに簡単になります。

6

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

例えば:

public class Outer{ 
   public class Inner {
   }
}

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

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

1
Steve B.

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

レコードについては、「inner.getClass()。getDeclaredField( "this $ 0")」が機能します。フィールドはプライベートなので、field.setAccessible(true)を呼び出す必要もあります。

1
Rich MacDonald

単純にこれを書くための問題はどこにありますか?

class OuterClass{
class InnerClass{
    OuterClass outerClass = OuterClass.this;
}

}

1
Igor

次のようなことはできませんか?

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

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

    public Outer get Outer() { return parent; }
}
0