web-dev-qa-db-ja.com

内部クラスオブジェクトから外部クラスオブジェクトを取得する

私は次のコードを持っています。内部クラスオブジェクトinnerの作成に使用した外部クラスオブジェクトを取得したい。どうすればいいですか?

public class OuterClass {

    public class InnerClass {
        private String name = "Peakit";
    }

    public static void main(String[] args) {
        OuterClass outer = new OuterClass();
        InnerClass inner = outer.new InnerClass();
       // How to get the same outer object which created the inner object back?
        OuterClass anotherOuter = ?? ;

        if(anotherOuter == outer) {
             System.out.println("Was able to reach out to the outer object via inner !!");
        } else {
             System.out.println("No luck :-( ");
        }
    }
}

編集:さて、あなたの一部は、メソッドを追加して内部クラスを変更することを提案しました:

public OuterClass outer() {
   return OuterClass.this;
}

しかし、内部クラスを変更するコントロールがない場合、(確認のために)内部クラスオブジェクトから対応する外部クラスオブジェクトを取得する他の方法はありますか?

219
peakit

内部クラス自体の中では、OuterClass.thisを使用できます。字句的に囲むインスタンスを参照できるこの式は、JLSでは Qualified this として記述されています。

私はthinkとは思いませんが、内部クラスのコードの外部からインスタンスを取得する方法はあります。もちろん、いつでも独自のプロパティを導入できます。

public OuterClass getOuter() {
    return OuterClass.this;
}

編集:実験により、外部クラスへの参照を保持するフィールドがパッケージレベルのアクセス権を持っているように見えます-少なくとも私が使用しているJDKでは。

編集:使用される名前(this$0isは実際にはJavaで有効ですが、 JLS は使用を推奨しません:

$文字は、機械的に生成されたソースコードでのみ使用するか、まれに、レガシーシステム上の既存の名前にアクセスする必要があります。

299
Jon Skeet

OuterClass.thisは外部クラスを参照します。

31
bmargulies

ジョブにリフレクションを使用することはできますが、すべきではありません。

import Java.lang.reflect.Field;

public class Outer {
    public class Inner {
    }

    public static void main(String[] args) throws Exception {

        // Create the inner instance
        Inner inner = new Outer().new Inner();

        // Get the implicit reference from the inner to the outer instance
        // ... make it accessible, as it has default visibility
        Field field = Inner.class.getDeclaredField("this$0");
        field.setAccessible(true);

        // Dereference and cast it
        Outer outer = (Outer) field.get(inner);
        System.out.println(outer);
    }
}

もちろん、暗黙の参照の名前はまったく信頼できないので、私が言ったように、あなたはすべきではありません:-)

21
Lukas Eder

この質問に対するより一般的な答えは、シャドウ化された変数とそのアクセス方法に関係します。

次の例(Oracleから)では、変数xinmain()シャドウイングTest.x

class Test {
    static int x = 1;
    public static void main(String[] args) {
        InnerClass innerClassInstance = new InnerClass()
        {
            public void printX()
            {
                System.out.print("x=" + x);
                System.out.println(", Test.this.x=" + Test.this.x);
            }
        }
        innerClassInstance.printX();
    }

    public abstract static class InnerClass
    {
        int x = 0;

        public InnerClass() { }

        public abstract void printX();
    }
}

このプログラムを実行すると印刷されます:

x=0, Test.this.x=1

詳細: http://docs.Oracle.com/javase/specs/jls/se7/html/jls-6.html#jls-6.6

2
Gladclef

内部クラスを変更するコントロールがない場合は、refectionが役立つ場合があります(ただしお勧めしません)。 this $ 0は、Innerクラスの参照であり、OuterクラスのどのインスタンスがInnerクラスの現在のインスタンスの作成に使用されたかを示します。

0
曹建发
/**
 * Not applicable to Static Inner Class (nested class)
 */
public static Object getDeclaringTopLevelClassObject(Object object) {
    if (object == null) {
        return null;
    }
    Class cls = object.getClass();
    if (cls == null) {
        return object;
    }
    Class outerCls = cls.getEnclosingClass();
    if (outerCls == null) {
        // this is top-level class
        return object;
    }
    // get outer class object
    Object outerObj = null;
    try {
        Field[] fields = cls.getDeclaredFields();
        for (Field field : fields) {
            if (field != null && field.getType() == outerCls
                    && field.getName() != null && field.getName().startsWith("this$")) {
                field.setAccessible(true);
                outerObj = field.get(object);
                break;
            }
        }
    } catch (Exception e) {
        e.printStackTrace();
    }
    return getDeclaringTopLevelClassObject(outerObj);
}

もちろん、暗黙的な参照の名前は信頼できないため、ジョブにリフレクションを使用しないでください。

0
Vali Zhao

私はこのようにしました:

public class CherryTree {
    public class Cherry {
        public final CherryTree cherryTree = CherryTree.this;
        // [...]
    }
    // [...]
}

もちろん、内部クラスを変更できるようにする必要があり、内部クラスオブジェクトを取得するすべての人が外部クラスオブジェクトにアクセスできるようになります。私の場合、それで十分です。

0
Chikyuno
public class Outer {


    public Inner getInner(){
        return new Inner(this,this.getClass());
    }

    class Inner {

        public Inner(Outer outer, Class<? extends Outer> aClass) {
            System.out.println(outer);
            System.out.println(aClass.getName());
            System.out.println();
        }
    }

    public static void main(String[] args) {
        new Outer().getInner();
    }
}
0
sjaojya

以下に例を示します。

// Test
public void foo() {
    C c = new C();
    A s;
    s = ((A.B)c).get();
    System.out.println(s.getR());
}

// classes
class C {}

class A {
   public class B extends C{
     A get() {return A.this;}
   }
   public String getR() {
     return "This is string";
   }
}
0
Ashish Rawat