web-dev-qa-db-de.com

Das äußere Klassenobjekt aus dem inneren Klassenobjekt herausholen

Ich habe den folgenden Code. Ich möchte das äußere Klassenobjekt erhalten, mit dem ich das innere Klassenobjekt inner erstellt habe. Wie kann ich es tun?

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 :-( ");
        }
    }
}

EDIT: Nun, einige von euch haben vorgeschlagen, die innere Klasse durch Hinzufügen einer Methode zu ändern:

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

Was aber, wenn ich keine Kontrolle über die innere Klasse habe, haben wir (nur zur Bestätigung) eine andere Möglichkeit, das entsprechende äußere Klassenobjekt aus dem inneren Klassenobjekt zu holen?

212
peakit

Innerhalb der inneren Klasse selbst können Sie OuterClass.this verwenden. Dieser Ausdruck, mit dem auf jede lexikalisch einschließende Instanz verwiesen werden kann, wird im JLS als Qualified this beschrieben.

Ich glaube nicht , dass es eine Möglichkeit gibt, die Instanz von außerhalb des Codes der inneren Klasse abzurufen. Natürlich können Sie jederzeit Ihre eigene Immobilie vorstellen:

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

EDIT: Experimentell hat das Feld, das den Verweis auf die äußere Klasse enthält, Zugriff auf Paketebene - zumindest mit dem von mir verwendeten JDK.

BEARBEITEN: Der verwendete Name (this$0) ist in Java gültig, obwohl das JLS von seiner Verwendung abrät:

Das Zeichen $ sollte nur in mechanisch generiertem Quellcode verwendet werden oder selten, um auf vorhandene Namen in älteren Systemen zuzugreifen.

301
Jon Skeet

OuterClass.this verweist auf die äußere Klasse.

30
bmargulies

Sie könnten Reflektion für den Job verwenden (sollten Sie jedoch nicht):

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);
    }
}

Natürlich ist der Name des impliziten Verweises absolut unzuverlässig, also sollte ich nicht sagen:

20
Lukas Eder

Die allgemeinere Antwort auf diese Frage beinhaltet schattierte Variablen und wie auf sie zugegriffen wird.

Im folgenden Beispiel (von Oracle) schattiert die Variable x in main ()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();
    }
}

Wenn Sie dieses Programm ausführen, wird Folgendes gedruckt:

x=0, Test.this.x=1

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

2
Gladclef

wenn Sie keine Kontrolle über die innere Klasse haben, kann Ihnen die Refection helfen (aber nicht empfehlen). Dieses $ 0 ist eine Referenz in der inneren Klasse, die angibt, welche Instanz der äußeren Klasse zum Erstellen der aktuellen Instanz der inneren Klasse verwendet wurde.

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);
}

Natürlich ist der Name des impliziten Verweises unzuverlässig, Sie sollten also keine Reflektion für den Job verwenden.

0
Vali Zhao

Ich habe es einfach so gemacht:

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

Natürlich müssen Sie die innere Klasse ändern können, und jeder, der das innere Klassenobjekt erhält, hat jetzt Zugriff auf das äußere Klassenobjekt. In meinem Fall ist es gut.

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

Hier ist das Beispiel:

// 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