Получение объекта внешнего класса из объекта внутреннего класса


у меня есть следующий код. Я хочу получить доступ к объекту внешнего класса, с помощью которого я создал объект внутреннего класса 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 :-( ");
        }
    }
}

EDIT: Ну, некоторые из вас, ребята предложили изменить внутренний класс, добавляя метод:

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

но что, если у меня нет контроля для изменения внутреннего класса, то (просто для подтверждения) у нас есть какой-то другой способ получить соответствующий внешний объект класса из внутреннего класса возражаете?

10 198

10 ответов:

внутри самого внутреннего класса вы можете использовать OuterClass.this. Это выражение, которое позволяет ссылаться на любой лексически заключающий экземпляр, описывается в JLS как квалификации this.

Я не думаю есть способ получить экземпляр из-за пределов кода внутреннего класса, хотя. Конечно, вы всегда можете ввести свое собственное свойство:

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

EDIT: экспериментируя, это выглядит как поле, содержащее ссылку на внешний класс имеет доступ на уровне пакета - по крайней мере, с JDK, который я использую.

изменить: имя используется (this)и фактически действителен в Java, хотя JLS препятствует его использованию:

The $ символ должен использоваться только в механически сгенерированный исходный код или, редко, чтобы получить доступ к уже существующим именам устаревшие системы.

OuterClass.this ссылки на внешний класс.

вы могли бы (но вы не должны) использовать отражение для задания:

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

конечно, имя неявной ссылки совершенно ненадежно, поэтому, как я уже сказал, Вы не должны: -)

более общий ответ на этот вопрос включает в себя затененные переменные и как они доступны.

в следующем примере (из Oracle), переменной x на main () затенение

Я думаю, что это может быть злоупотребление использование внутреннего класса. Мне кажется, что то, что вы хотите сделать, нарушает фундаментальные понятия объектно-ориентированного программирования. Если вы хотите получить доступ к внешнему классу из внутреннего класса, включите ссылку на внешний класс, чтобы у вас был доступ к нему. Когда вы должны делать сложные вещи, как это обычно является признаком того, что вы должны пересмотреть свой выбор дизайна.

вот пример:

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

Я просто сделал это так:

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

конечно, вам нужно иметь возможность изменять внутренний класс, и каждый, кто получает объект внутреннего класса, теперь имеет доступ к объекту внешнего класса. В моем случае это просто прекрасно.

Если у вас нет управления для изменения внутреннего класса, отражение может помочь вам (но не рекомендовать). это$0 является ссылкой во внутреннем классе, который говорит, какой экземпляр внешнего класса был использован для создания текущего экземпляра внутреннего класса.

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

конечно, имя неявной ссылки ненадежно, поэтому вы не должны использовать отражение для задания.