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