java - una - Conseguir el objeto de clase exterior del objeto de clase interior




obtener atributos de una clase java (6)

Aquí está el ejemplo:

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

tengo el siguiente código. Quiero obtener el objeto de la clase externa mediante el cual creé el objeto de la clase inner . ¿Cómo puedo hacerlo?

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

EDITAR: Bueno, algunos de ustedes sugirieron modificar la clase interna agregando un método:

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

Pero ¿qué pasa si no tengo el control para modificar la clase interna, entonces (solo para confirmar) tenemos otra forma de obtener el objeto de la clase externa correspondiente del objeto de la clase interna?


Dentro de la propia clase interna, puedes usar OuterClass.this . Esta expresión, que permite referirse a cualquier instancia que encierra léxicamente, se describe en el JLS como Calificado como this .

Sin embargo, no creo que haya una manera de obtener la instancia desde fuera del código de la clase interna. Por supuesto, siempre puedes introducir tu propia propiedad:

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

EDITAR: según la experimentación, parece que el campo que contiene la referencia a la clase externa tiene acceso a nivel de paquete, al menos con el JDK que estoy usando.

EDITAR: El nombre utilizado ( this$0 ) es realmente válido en Java, aunque el JLS desaconseja su uso:

El carácter $ debe usarse solo en el código fuente generado mecánicamente o, raramente, para acceder a nombres preexistentes en sistemas heredados.


Podrías (pero no deberías) usar la reflexión para el trabajo:

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

Por supuesto, el nombre de la referencia implícita es absolutamente poco confiable, así que como dije, no deberías :-)


Si no tiene control para modificar la clase interna, la respuesta puede ayudarlo (pero no recomendar). este $ 0 es una referencia en la clase interna que indica qué instancia de la clase externa se usó para crear la instancia actual de la clase interna.


OuterClass.this referencia a la clase externa.


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

Por supuesto, el nombre de la referencia implícita no es confiable, por lo que no debe usar la reflexión para el trabajo.





inner-classes