[java] 외부 Java 클래스가 내부 클래스 전용 멤버에 액세스 할 수있는 이유는 무엇입니까?

외부 클래스가 내부 클래스 전용 인스턴스 변수에 액세스 할 수 있음을 관찰했습니다. 이것이 어떻게 가능한지? 다음은 동일한 내용을 보여주는 샘플 코드입니다.

class ABC{
    class XYZ{
        private int x=10;
    }

    public static void main(String... args){
        ABC.XYZ xx = new ABC().new XYZ();
        System.out.println("Hello :: "+xx.x); ///Why is this allowed??
    }
}

이 동작이 왜 허용됩니까?



답변

내부 클래스는 원래 외부 클래스에 속하는 일부 기능을 명확하게 분리하는 방법입니다. 다음 두 가지 요구 사항이있을 때 사용하도록 만들어졌습니다.

  1. 외부 클래스의 일부 기능은 별도의 클래스로 구현 된 경우 가장 분명합니다.
  2. 별도의 클래스에 있지만 기능은 외부 클래스의 작동 방식과 매우 밀접한 관련이 있습니다.

이러한 요구 사항이 주어지면 내부 클래스는 외부 클래스에 완전히 액세스 할 수 있습니다. 기본적으로 외부 클래스의 멤버이므로 개인을 포함하여 외부 클래스의 메서드 및 속성에 액세스 할 수 있습니다.


답변

내부 클래스의 비공개 멤버를 숨기려면 공개 멤버와의 인터페이스를 정의하고이 인터페이스를 구현하는 익명의 내부 클래스를 만들 수 있습니다. 벨로우즈 예제 :

class ABC{
    private interface MyInterface{
         void printInt();
    }

    private static MyInterface mMember = new MyInterface(){
        private int x=10;

        public void printInt(){
            System.out.println(String.valueOf(x));
        }
    };

    public static void main(String... args){
        System.out.println("Hello :: "+mMember.x); ///not allowed
        mMember.printInt(); // allowed
    }
}


답변

내부 클래스는 (액세스 제어를 위해) 포함 클래스의 일부로 간주됩니다. 이것은 모든 개인에 대한 모든 액세스 권한을 의미합니다.

이것이 구현되는 방식은 합성 패키지로 보호되는 메소드를 사용하는 것입니다. 내부 클래스는 동일한 패키지 (ABC $ XYZ)의 별도 클래스로 컴파일됩니다. JVM은이 분리 레벨을 직접 지원하지 않으므로 바이트 코드 레벨 ABC $ XYZ에는 외부 클래스가 개인 메소드 / 필드에 도달하는 데 사용하는 패키지 보호 메소드가 있습니다.


답변

이와 비슷한 또 다른 질문에는 정답이 있습니다.
왜 중첩 클래스의 개인 멤버에 둘러싸는 클래스의 메소드로 액세스 할 수 있습니까?

JLS 에 개인 범위 지정이 정의되어 있습니다 -접근성 결정 :

그렇지 않으면 멤버 또는 생성자가 비공개로 선언 된 경우 멤버 또는 생성자의 선언 을 포함하는 최상위 클래스 (§7.6) 본문 내에서 발생하는 경우에만 액세스가 허용됩니다.


답변

내부 클래스에 대한 IMHO의 중요한 사용 사례는 팩토리 패턴입니다. 엔 클로징 클래스는 액세스 제한이없는 내부 클래스의 인스턴스를 준비하고 인스턴스를 외부 세계로 전달할 수 있으며 개인 액세스는 존중됩니다.

모순에서 abyx은 아래 그림과 같이 클래스의 정적을 선언, 바깥 쪽 클래스에없는 변경 액세스 제한을한다. 또한 동일한 엔 클로징 클래스에서 정적 클래스 간의 액세스 제한이 작동 중입니다. 놀랐습니다 …

class MyPrivates {
    static class Inner1 { private int test1 = 2; }
    static class Inner2 { private int test2 = new Inner1().test1; }

    public static void main(String[] args) {
        System.out.println("Inner : "+new Inner2().test2);
    }
}


답변

액세스 제한은 클래스별로 이루어집니다. 클래스에서 선언 된 메소드가 모든 인스턴스 / 클래스 멤버에 액세스 할 수있는 방법은 없습니다. 이는 내부 클래스가 외부 클래스의 멤버에게도 액세스 할 수 있고 외부 클래스는 내부 클래스의 멤버에 대해 액세스 할 수없는 이유입니다.

클래스를 다른 클래스에 넣으면 구현과 밀접하게 관련되어 있으며 구현의 일부는 다른 부분에 액세스해야합니다.


답변

내부 클래스의 논리는 외부 클래스에서 내부 클래스를 만드는 경우 몇 가지 사항을 공유해야하기 때문에 “일반”클래스보다 유연성을 가질 수 있다는 것입니다.

귀하의 경우 클래스가 서로의 내부 작업을 볼 수없는 경우-기본적으로 내부 클래스가 단순히 일반 클래스가 될 수 있음을 의미하면 내부 클래스를로 선언 할 수 있습니다 static class XYZ. 를 사용 static하면 상태를 공유하지 않을 것입니다 (예를 들어 new ABC().new XYZ()작동하지 않으며 사용할 필요가 있습니다) new ABC.XYZ().
그렇다면 XYZ실제로 내부 클래스가되어야 하는지 , 아니면 그 자체로 가치가 있는지 생각 해야합니다. 때로는 정적 내부 클래스를 만드는 것이 합리적입니다 (예 : 외부 클래스가 사용하는 인터페이스를 구현하는 작은 클래스가 필요한 경우 다른 곳에서는 도움이되지 않음). 그것은 외부 계급이되었을 것입니다.