Ottenere l’object class esterna dall’object class interna

Ho il codice seguente. Voglio ottenere l’object class esterna usando il quale ho creato l’object inner class inner . Come posso farlo?

 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: Beh, alcuni di voi ragazzi hanno suggerito di modificare la class interna aggiungendo un metodo:

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

Ma cosa succede se non ho il controllo per modificare la class interna, quindi (solo per confermare) abbiamo qualche altro modo per ottenere l’object class esterna corrispondente dall’object class interna?

All’interno della class interna stessa, puoi usare OuterClass.this . Questa espressione, che consente di fare riferimento a qualsiasi istanza che include il lessico, è descritta nel JLS come Qualificato .

Non penso che ci sia un modo per ottenere l’istanza dall’esterno del codice della class interna. Certo, puoi sempre presentare la tua proprietà:

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

EDIT: Per sperimentazione, sembra che il campo che contiene il riferimento alla class esterna abbia accesso a livello di pacchetto, almeno con il JDK che sto usando.

EDIT: il nome usato ( this$0 ) è effettivamente valido in Java, anche se il JLS scoraggia il suo uso:

Il carattere $ deve essere utilizzato solo in codice sorgente generato meccanicamente o, raramente, per accedere a nomi preesistenti su sistemi legacy.

OuterClass.this riferimenti alla class esterna.

Potresti (ma non dovresti) usare la riflessione per il lavoro:

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

Certo, il nome del riferimento implicito è assolutamente inaffidabile, quindi come ho detto, non dovresti 🙂

La risposta più generale a questa domanda riguarda le variabili ombreggiate e il modo in cui sono accessibili.

Nell’esempio seguente (da Oracle), la variabile x in main () ombreggia 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(); } } 

L’esecuzione di questo programma stampa:

 x=0, Test.this.x=1 

Ulteriori informazioni su: http://docs.oracle.com/javase/specs/jls/se7/html/jls-6.html#jls-6.6

Penso che questo possa essere un abuso dell’uso di una class interiore. Mi sembra che quello che vuoi fare è violare i concetti fondamentali della programmazione orientata agli oggetti. Se si desidera accedere alla class esterna dalla class interna, includere quindi un riferimento alla class esterna in modo da potervi accedere. Quando devi fare cose complicate come questa, di solito è un segno che devi riconsiderare le tue scelte progettuali.

Ecco l’esempio:

 // Test public void foo() { C c = new C(); A s; s = ((AB)c).get(); System.out.println(s.getR()); } // classs class C {} class A { public class B extends C{ A get() {return A.this;} } public String getR() { return "This is string"; } } 

L’ho fatto così:

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

Naturalmente è necessario essere in grado di modificare la class interna e chiunque abbia l’object class interna abbia accesso all’object class esterna ora. Nel mio caso va bene.

se non hai il controllo per modificare la class interiore, il refection può aiutarti (ma non consigliarlo). questo $ 0 è un riferimento nella class Inner che indica quale istanza della class Outer è stata utilizzata per creare l’istanza corrente della class Inner.

 public class Outer { public Inner getInner(){ return new Inner(this,this.getClass()); } class Inner { public Inner(Outer outer, Class aClass) { System.out.println(outer); System.out.println(aClass.getName()); System.out.println(); } } public static void main(String[] args) { new Outer().getInner(); } } 
 /** * 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); } 

Naturalmente, il nome del riferimento implicito è inaffidabile, quindi non si dovrebbe usare la riflessione per il lavoro.