내부 클래스가 언어 버전 1.1에서 Java에 추가되었을 때 원래는 1.0 호환 코드로의 변환으로 정의되었습니다. 이 변환의 예를 살펴보면 내부 클래스가 실제로 작동하는 방식이 훨씬 더 명확해질 것이라고 생각합니다.
Ian Roberts의 답변 코드를 고려하십시오.
public class Foo {
int val;
public Foo(int v) { val = v; }
class Bar {
public void printVal() {
System.out.println(val);
}
}
public Bar createBar() {
return new Bar();
}
}
1.0 호환 코드로 변환하면 내부 클래스 Bar는 다음과 같이됩니다.
class Foo$Bar {
private Foo this$0;
Foo$Bar(Foo outerThis) {
this.this$0 = outerThis;
}
public void printVal() {
System.out.println(this$0.val);
}
}
내부 클래스 이름에는 고유하게 만들기 위해 외부 클래스 이름이 접두어로 붙습니다. this$0외부의 복사본을 보유하는 숨겨진 개인 구성원이 추가 this됩니다. 그리고 해당 멤버를 초기화하기 위해 숨겨진 생성자가 생성됩니다.
createBar메서드 를 살펴보면 다음과 같이 변환됩니다.
public Foo$Bar createBar() {
return new Foo$Bar(this);
}
이제 다음 코드를 실행하면 어떤 일이 발생하는지 살펴 보겠습니다.
Foo f = new Foo(5);
Foo.Bar b = f.createBar();
b.printVal();
먼저 인스턴스를 인스턴스화 Foo하고 val멤버를 5 (즉 f.val = 5) 로 초기화합니다 .
다음으로를 호출 f.createBar()하여의 인스턴스를 인스턴스화 Foo$Bar하고 this$0멤버를 this전달 된 값 createBar(예 :)으로 초기화합니다 b.this$0 = f.
마지막으로 우리는 전화를 b.printVal()인쇄 할 수있는 b.this$0.val인 f.val5이다.
이제 그것은 내부 클래스의 정기적 인 인스턴스화였습니다. Bar외부에서 인스턴스화 할 때 어떤 일이 발생하는지 살펴 보겠습니다 Foo.
Foo f = new Foo(5);
Foo.Bar b = f.new Bar();
b.printVal();
1.0 변환을 다시 적용하면 두 번째 줄은 다음과 같이됩니다.
Foo$Bar b = new Foo$Bar(f);
이것은 f.createBar()호출 과 거의 동일합니다 . 다시 우리는 인스턴스를 인스턴스화 Foo$Bar하고 this$0멤버를 f로 초기화합니다 . 다시 b.this$0 = f.
전화 할 때 그리고 다시 b.printVal(), 당신은 인쇄 b.thi$0.val되는 f.val5이다.
기억해야 할 핵심 사항은 내부 클래스 this에 외부 클래스 의 복사본을 보유하는 숨겨진 멤버가 있다는 것 입니다. 외부 클래스 내에서 내부 클래스를 인스턴스화하면 현재 값으로 암시 적으로 초기화됩니다 this. 외부 클래스 외부에서 내부 클래스를 인스턴스화 할 때 new키워드 의 접두사를 통해 사용할 외부 클래스의 인스턴스를 명시 적으로 지정 합니다.