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


177

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

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??
    }
}

이 동작이 왜 허용됩니까?


이 질문은 내가 주석을 볼 때까지 꽤 오랫동안 혼란스러워했다. ... 내 기계에서 xx.x에 액세스 할 수없는 이유를 설명합니다.
Wang Sheng

4
주석이 혼란 스러웠습니다. 위의 코드를 Java 8에서 실행하면 컴파일 및 실행됩니다. xx.x에 액세스 할 수 있습니다.
leon

어리석은 질문에 대답하지 않은 수락 된 답변을 수락하지 말고 아래에있는 Martin Andersson의 답변을 수락하십시오.
temporary_user_name

다음 구문은 절대적으로 끔찍합니다 :new ABC().new XYZ()
Josh M.

답변:


80

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

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

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


217
이 답변은 중첩 클래스가 외부 클래스의 비공개 멤버에 액세스 할 수있는 이유를 설명합니다. 그러나 문제는 외부 클래스가 중첩 클래스의 개인 멤버에 액세스하는 이유입니다.
앤드류

13
그냥 추가 "그 반대"에 주어 이러한 요구 사항, 내부 클래스는 외부 클래스에 대한 전체 액세스 권한이 지금은 질문에 대한 답.
anthropomo

13
이것은이 문제에 대한 정답이 아닙니다. stackoverflow.com/questions/19747812/…
Colin Su

4
@anthropomo : 아뇨. 외부 클래스가 내부 클래스의 개인 멤버에 액세스 할 수 없으면 두 요구 사항 모두 완벽하게 실현 가능합니다.
또는 매퍼

이것이 특히 유용한 좋은 예는 빌더 패턴 stackoverflow.com/a/1953567/1262000 입니다. 부모 클래스는 빌더를 가져 와서 모든 멤버 변수에 액세스하는 생성자를 필요로합니다. 그렇지 않으면 모든 개인 멤버 변수가있는 부모 클래스에 개인 생성자가 있어야합니다.
vikky.rk

62

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

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
    }
}

이것은 훌륭한 코드 스 니펫입니다. 내가 필요한 것만 감사!
kevinarpe

실행할 수있는 코드를 제공하십시오. 개인 변수에 액세스 할 수없는 이유는 무엇입니까?
androidyue

7
그러나 내부 클래스는 익명입니다. 해당 내부 클래스의 인스턴스를 여러 개 만들거나 변수 선언 등에 해당 내부 클래스를 사용할 수 없습니다.
또는 Mapper

@OR Mapper이므로 x여기에 공개되어 있어도 허용되지 않습니다 mMember.x.
MAC

54

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

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


17

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

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

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


이 스 니펫이 내 질문에 잘 대답 할 수 있다고 생각합니다.
shen

5

내부 클래스에 대한 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);
    }
}

1
좋은 의견이지만 대답이 없습니다.
9:42에 sep

@cerving 이것은 실제로이 기괴한 디자인 결정의 실제 사용을 볼 수있는 유일한 해답입니다. 문제는 왜 이런 식으로 결정 되었는가에 관한 것이 었습니다. 이것은 외부 클래스가 내부 클래스에서 액세스하기를 원하는 것과 다른 비 관련 클래스가 액세스하기를 원하는 것의 차이를 보여주는 큰 이유입니다.
et_l

3

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

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


3

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

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


2
외부 클래스는 정적 내부 클래스 의 전용 멤버에도 액세스 할 수 있으므로 static 과는 아무런 관련이 없습니다 . "교실이 서로의 내부 활동을 볼 수 있다는 것은 말이되지 않습니다."라고 말하지만, 반드시 그런 것은 아닙니다. 내부 클래스가 외부 클래스의 내부 활동을 보는 것이 합리적이라면 어떻게됩니까? 그 반대?
OR Mapper

3

Thilo는 첫 번째 질문 인 "어떻게 가능합니까?" 에 대한 좋은 답변 을 추가했습니다 . 두 번째 질문에 대해 좀 더 자세히 설명하겠습니다. 왜이 동작이 허용됩니까?

우선,이 동작이 정적 클래스가 아닌 중첩 클래스 인 내부 클래스로 제한되지 않는다는 것을 완벽하게 분명히합시다. 이 동작은 정적이어야하고 둘러싸는 인스턴스를 가질 수없는 중첩 된 열거 형 및 인터페이스를 포함하여 모든 중첩 된 유형에 허용됩니다. 기본적으로이 모델은 다음 문장으로 단순화됩니다. 중첩 코드는 코드를 둘러싸는 모든 권한을 가지며 그 반대도 마찬가지입니다.

그럼 왜? 예제가 그 요점을 더 잘 설명한다고 생각합니다.

몸과 뇌를 생각하십시오. 헤로인을 팔에 주사하면 뇌가 높아집니다. 예를 들어 말벌과 같이 뇌의 편도 영역이 개인의 안전에 위협이된다고 생각하는 것을 보면, 몸을 다른 방향으로 돌리고 언덕을 두 번 "생각"하지 않고도 언덕을 향해 달리게 할 것입니다.

따라서 뇌는 신체의 본질적인 부분이며 이상하게도 그 반대의 경우도 마찬가지입니다. 밀접하게 관련된 엔터티 간의 액세스 제어를 사용하면 관계에 대한 주장을 상실하게됩니다. 액세스 제어가 필요한 경우 클래스를 더 뚜렷한 단위로 분리해야합니다. 그때까지는 같은 단위입니다. 추가 연구의 추진 사례는 Java가 Iterator일반적으로 구현 되는 방식을 살펴 보는 것 입니다.

둘러싸는 코드에서 중첩 된 코드로의 무제한 액세스는 대부분 중첩 된 유형의 필드 및 메소드에 액세스 수정자를 추가하는 데 쓸모가 없습니다. 그렇게하면 혼란이 가중되고 Java 프로그래밍 언어의 새로운 사용자에게 잘못된 안전감을 제공 할 수 있습니다.


1
이것은 진짜 대답이 될 것입니다. 매우 명확하고 철저합니다. 그 대신에 받아 들여진 대답은 그 질문을 다루지 않습니다.
temporary_user_name

IMO 여전히 내부 클래스에 개인 필드를 쉽게 추가 할 수없는 이유에 대해 여전히 대답하지 않습니다.이 클래스는 외부 클래스가 직접 액세스 할 수 없습니다. 내가 틀리지 않는 한, 이것은 내부 클래스의 주요 사례 중 하나를 파괴합니다-단기 "구조와 같은"불변 유형을 만듭니다. FWIW C #은 다음을 행복하게 지원합니다 : repl.it/repls/VengefulCheeryInverse
Josh M.

-1

내부 클래스는 외부 클래스의 속성으로 간주됩니다. 따라서 내부 클래스 인스턴스 변수가 개인용이든 아니든 외부 클래스는 다른 개인용 속성 (변수)에 액세스하는 것처럼 문제없이 액세스 할 수 있습니다.

class Outer{

private int a;

class Inner{
private int b=0;
}

void outMethod(){
a = new Inner().b;
}
}

-2

main()메소드가 ABC클래스 에 있기 때문에 자체 내부 클래스에 액세스 할 수 있습니다.


2
문제는 ABC클래스의 멤버가 클래스에 중첩 된 클래스에 액세스 할 수 있는지 여부가 아니라 Java 에서 클래스에 중첩 된 클래스의 개인 멤버에 ABC액세스 할 수있는 이유 입니다. ABC
또는 매퍼

질문을받은 당일에 질문에 대답했습니다. 2 년 후 누군가가이 질문을 편집했고, 3 년 후에 공감이 나왔습니다. 질문을 편집 한 사람이 질문의 문구를 너무 많이 변경했다고 확신합니다.
aberrant80
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.