다음 코드가 있습니다. 내부 클래스 객체를 만든 외부 클래스 객체를 잡고 싶습니다 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;
}
그러나 내부 클래스를 수정할 수있는 컨트롤이 없다면 내부 클래스 객체에서 해당 외부 클래스 객체를 얻는 다른 방법이 있습니까?
답변
내부 클래스 자체에서을 사용할 수 있습니다 OuterClass.this
. 어휘로 묶는 인스턴스를 참조 할 수있는이 표현식은 JLS에서 Qualifiedthis
로 설명됩니다 .
내부 클래스의 코드 외부에서 인스턴스를 가져 오는 방법 이 없다고 생각 합니다. 물론 언제든지 자신의 재산을 소개 할 수 있습니다.
public OuterClass getOuter() {
return OuterClass.this;
}
편집 : 실험에 따르면 외부 클래스에 대한 참조를 보유하고있는 필드가 패키지 수준 액세스 권한을 가지고있는 것처럼 보입니다. 적어도 사용중인 JDK를 사용하십시오.
편집 : 사용 된 이름 ( this$0
) 은 Java에서 실제로 유효하지만 JLS 는 사용을 권장하지 않습니다.
이
$
문자는 기계적으로 생성 된 소스 코드에서만 사용되거나 레거시 시스템의 기존 이름에 액세스하는 경우는 거의 없습니다.
답변
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$0");
field.setAccessible(true);
// Dereference and cast it
Outer outer = (Outer) field.get(inner);
System.out.println(outer);
}
}
물론 암시 적 참조의 이름은 완전히 신뢰할 수 없으므로 내가 말했듯이 :-)해서는 안됩니다.
답변
이 질문에 대한보다 일반적인 대답은 그림자 변수와 변수에 액세스하는 방법입니다.
다음 예제 (Oracle의) 에서 main () 의 변수 x 는 Shadow.Test입니다 .
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 에서 자세히 알아보십시오.
답변
예를 들면 다음과 같습니다.
// 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";
}
}
답변
내부 클래스를 수정할 수있는 권한이없는 경우 리 펙션이 도움이 될 수 있습니다 (권장하지는 않음). this $ 0은 Inner 클래스의 참조로, Inner 클래스의 현재 인스턴스를 만드는 데 사용 된 Outer 클래스의 인스턴스를 알려줍니다.
답변
/**
* 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);
}
물론 암시 적 참조의 이름은 신뢰할 수 없으므로 작업에 반영을 사용해서는 안됩니다.