익명 클래스를 사용하면 실제로 "이름이없는"중첩 클래스를 선언합니다. 중첩 클래스의 경우 컴파일러는 인수로 사용하는 모든 변수를 인수로 사용하는 생성자를 사용하여 새 독립 실행 형 공용 클래스를 생성합니다 ( "명명 된"중첩 클래스의 경우 항상 원본 / 클래 싱 클래스의 인스턴스 임). 런타임 환경에는 중첩 클래스에 대한 개념이 없기 때문에 중첩 클래스에서 독립형 클래스로 (자동) 변환해야합니다.
이 코드를 예로 들어 보겠습니다.
public class EnclosingClass {
public void someMethod() {
String shared = "hello";
new Thread() {
public void run() {
// this is not valid, won't compile
System.out.println(shared); // this instance expects shared to point to the reference where the String object "hello" lives in heap
}
}.start();
// change the reference 'shared' points to, with a new value
shared = "other hello";
System.out.println(shared);
}
}
이것은 컴파일러가 후드에서하는 일이기 때문에 작동하지 않습니다.
public void someMethod() {
String shared = "hello";
new EnclosingClass$1(shared).start();
// change the reference 'shared' points to, with a new value
shared = "other hello";
System.out.println(shared);
}
원래의 익명 클래스는 컴파일러가 생성하는 독립형 클래스로 대체됩니다 (코드는 정확하지 않지만 좋은 아이디어를 제공해야합니다).
public class EnclosingClass$1 extends Thread {
String shared;
public EnclosingClass$1(String shared) {
this.shared = shared;
}
public void run() {
System.out.println(shared);
}
}
보시다시피 독립형 클래스는 공유 객체에 대한 참조를 보유하고 있으며 Java의 모든 것은 값을 전달한다는 점을 기억하십시오. 따라서 EnclosingClass의 'shared'참조 변수가 변경 되더라도 가리키는 인스턴스는 수정되지 않습니다. 익명 클래스의 Enclosing $ 1과 같은 다른 모든 참조 변수는이를 인식하지 못합니다. 이것이 컴파일러가이 '공유'변수를 최종 변수로 선언하도록하는 주된 이유입니다. 따라서 이러한 유형의 동작은 이미 실행중인 코드에 영향을 미치지 않습니다.
이제 이것은 익명 클래스 내에서 인스턴스 변수를 사용할 때 발생하는 현상입니다 (문제를 해결하고 로직을 "인스턴스"메서드 또는 클래스 생성자로 이동하려면 수행해야합니다).
public class EnclosingClass {
String shared = "hello";
public void someMethod() {
new Thread() {
public void run() {
System.out.println(shared); // this is perfectly valid
}
}.start();
// change the reference 'shared' points to, with a new value
shared = "other hello";
System.out.println(shared);
}
}
컴파일러가 코드를 수정하여 새로 생성 된 클래스 Enclosing $ 1이 인스턴스화 된 EnclosingClass 인스턴스에 대한 참조를 보유하기 때문에 이것은 잘 컴파일됩니다 (이것은 단지 표현 일뿐입니다).
public void someMethod() {
new EnclosingClass$1(this).start();
// change the reference 'shared' points to, with a new value
shared = "other hello";
System.out.println(shared);
}
public class EnclosingClass$1 extends Thread {
EnclosingClass enclosing;
public EnclosingClass$1(EnclosingClass enclosing) {
this.enclosing = enclosing;
}
public void run() {
System.out.println(enclosing.shared);
}
}
이와 같이 EnclosingClass에서 'shared'참조 변수가 재 할당되고 Thread # run ()을 호출하기 전에이 문제가 발생하면 EnclosingClass $ 1 # enclosing 변수가 참조를 유지하므로 "other hello"가 두 번 인쇄됩니다. 선언 된 클래스의 개체에 대한 속성이므로 해당 개체의 모든 특성에 대한 변경 내용은 EnclosingClass $ 1 인스턴스에 표시됩니다.
주제에 대한 자세한 내용은 다음과 같은 우수한 블로그 게시물을 참조하십시오 (저는 작성하지 않음). http://kevinboone.net/java_inner.html