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

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

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

Ответ 1

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

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

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

ИЗМЕНИТЬ: По опыту, похоже, что поле, содержащее ссылку на внешний класс, имеет доступ к уровню пакета - по крайней мере, с использованием JDK, который я использую.

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

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

Ответ 2

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

Ответ 3

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

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

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

Ответ 4

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

Ответ 5

Вот пример:

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

Ответ 6

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

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

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

Ответ 7

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

В следующем примере (из 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

Ответ 8

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

Ответ 9

открытый класс 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();
}

}