Получение объекта внешнего класса из объекта внутреннего класса
у меня есть следующий код. Я хочу получить доступ к объекту внешнего класса, с помощью которого я создал объект внутреннего класса 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 ответов:
внутри самого внутреннего класса вы можете использовать
OuterClass.this
. Это выражение, которое позволяет ссылаться на любой лексически заключающий экземпляр, описывается в JLS как квалификацииthis
.Я не думаю есть способ получить экземпляр из-за пределов кода внутреннего класса, хотя. Конечно, вы всегда можете ввести свое собственное свойство:
public OuterClass getOuter() { return OuterClass.this; }
EDIT: экспериментируя, это выглядит как поле, содержащее ссылку на внешний класс имеет доступ на уровне пакета - по крайней мере, с JDK, который я использую.
изменить: имя используется (
this
)и фактически действителен в Java, хотя JLS препятствует его использованию:The
$
символ должен использоваться только в механически сгенерированный исходный код или, редко, чтобы получить доступ к уже существующим именам устаревшие системы.
вы могли бы (но вы не должны) использовать отражение для задания:
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); }
конечно, имя неявной ссылки ненадежно, поэтому вы не должны использовать отражение для задания.