Domanda

Ho il seguente codice. Voglio ottenere l'oggetto di classe esterno usando il quale ho creato l'oggetto di classe interno 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: Bene, alcuni di voi ragazzi hanno suggerito di modificare la classe interna aggiungendo un metodo:

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

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

È stato utile?

Soluzione

All'interno della stessa classe interna, puoi usare OuterClass.this . Questa espressione, che consente di fare riferimento a qualsiasi istanza che racchiude in modo lessicale, è descritta in JLS come qualificato .

Non penso che ci sia un modo per ottenere l'istanza al di fuori del codice della classe interna. Naturalmente, puoi sempre presentare la tua proprietà:

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

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

EDIT: il nome utilizzato ( this $ 0 ) è effettivamente valido in Java, sebbene JLS scoraggia il suo utilizzo:

  

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

Altri suggerimenti

OuterClass.this fa riferimento alla classe 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<*>");
        field.setAccessible(true);

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

Naturalmente, il nome del riferimento implicito è assolutamente inaffidabile, quindi, come ho detto, non dovresti :-)

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

Nel seguente esempio (da Oracle), la variabile x in main () è in ombra 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 stamperà:

x=0, Test.this.x=1

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

Ecco l'esempio:

// 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";
   }
}

L'ho appena fatto in questo modo:

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

Ovviamente devi essere in grado di modificare la classe interna e tutti coloro che ottengono l'oggetto della classe interna hanno ora accesso all'oggetto della classe esterna. Nel mio caso va bene.

se non hai il controllo per modificare la classe interna, la refection può aiutarti (ma non raccomandare). questo $ 0 è riferimento nella classe interna che indica quale istanza della classe esterna è stata utilizzata per creare l'istanza corrente della classe interna.

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();
    }
}
/**
 * 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<*>quot;)) {
                field.setAccessible(true);
                outerObj = field.get(object);
                break;
            }
        }
    } catch (Exception e) {
        e.printStackTrace();
    }
    return getDeclaringTopLevelClassObject(outerObj);
}

Ovviamente, il nome del riferimento implicito è inaffidabile, quindi non dovresti usare la riflessione per il lavoro.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top