source

내부 클래스 개체에서 외부 클래스 개체를 가져오는 중

goodcode 2022. 8. 25. 23:52
반응형

내부 클래스 개체에서 외부 클래스 개체를 가져오는 중

나는 다음과 같은 코드를 가지고 있습니다.내부 클래스 개체를 만든 외부 클래스 개체를 가져오고 싶다.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에서는 Qualified로 기술되어 있습니다.

내부 계급의 코드 외부에서 인스턴스를 가져올 방법은 없다고 생각합니다.물론 언제든지 자신의 자산을 소개할 수 있습니다.

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

EDIT: 실험 결과 외부 클래스에 대한 참조를 유지하는 필드에는 패키지 수준의 액세스 권한이 있는 것 같습니다(적어도 사용 중인 JDK).

EDIT: 사용된 이름(this$0JLS에서는 사용을 권장하지 않지만 실제로는 Java에서 유효합니다.

$문자는 기계적으로 생성된 소스 코드 또는 드물게 레거시 시스템의 기존 이름에 액세스할 때만 사용해야 합니다.

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에서) 변수 x in main()섀도우링 테스트입니다.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 를 참조해 주세요.

다음은 예를 제시하겠습니다.

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

내부 클래스를 수정할 수 있는 제어 권한이 없는 경우, 리페션이 도움이 될 수 있습니다(권장되지는 않음).이 $0은 Inner 클래스의 현재 인스턴스를 만들기 위해 사용된 Outer 클래스의 인스턴스를 나타내는 Inner 클래스의 참조입니다.

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

물론 암묵적 참조의 이름은 신뢰할 수 없으므로 작업에 반영을 사용해서는 안 됩니다.

언급URL : https://stackoverflow.com/questions/1816458/getting-hold-of-the-outer-class-object-from-the-inner-class-object

반응형