Получение внешнего объекта класса от внутреннего объекта класса - PullRequest
219 голосов
/ 29 ноября 2009

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

РЕДАКТИРОВАТЬ: Ну, некоторые из вас, ребята, предложили изменить внутренний класс, добавив метод:

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

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

Ответы [ 9 ]

299 голосов
/ 29 ноября 2009

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

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

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

РЕДАКТИРОВАТЬ: Экспериментально похоже, что поле, содержащее ссылку на внешний класс, имеет доступ на уровне пакета - по крайней мере, с JDKс помощью.

РЕДАКТИРОВАТЬ: Используемое имя (this$0) действительно действительно в Java, хотя JLS препятствует его использованию:

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

31 голосов
/ 29 ноября 2009

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

21 голосов
/ 07 марта 2013

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

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

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

2 голосов
/ 12 августа 2016

Более общий ответ на этот вопрос касается теневых переменных и того, как они доступны.

В следующем примере (из Oracle) переменная x в 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();
    }
}

При запуске этой программы будет напечатано:

x=0, Test.this.x=1

Больше на: http://docs.oracle.com/javase/specs/jls/se7/html/jls-6.html#jls-6.6

0 голосов
/ 31 июля 2018
/**
 * 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);
}

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

0 голосов
/ 22 марта 2018
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 голосов
/ 27 апреля 2017

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

0 голосов
/ 04 августа 2016

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

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

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

0 голосов
/ 08 мая 2016

Вот пример:

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