2010-08-23 7 views
2

로컬 내부 클래스를 정의 할 때 클래스 만 참조하는 포함 메서드의 로컬 변수에 액세스하는 것이 안전합니까? 그래서 같이 : 내 예에서로컬 내부 클래스 메서드 포함 로컬 변수에 안전하게 액세스

public Bar containingMethod() 
{ 
    Foo foo = new Foo(); 
    Bar bar = new Bar() 
    { 
     public void baz() 
     { 
      System.out.println("Accessing foo: " + foo.getValue()); 
     } 
    }; 
    return bar; 
}; 

나는 정의되는 클래스가 foo에 대한 참조가 있는지 모르겠어요 위. 문제는 안전하고 OK 일 경우입니까 아니면 bar.baz()을 호출하기 전에 foo가 가비지 수집 될 위험이 있습니까?

+0

안전하지 않을뿐만 아니라 합법적이지 않습니다. 둘 모두를 '최종'으로 설정하면 안전하고 합법적입니다. – EJP

답변

4

안전하지만 foo가 final 일 필요가 있습니다 (그렇지 않으면 컴파일 오류가 발생합니다).

후드 아래에 바에 참조가 포함되어 있기 때문에 Foo는 가비지 수집되지 않습니다.

foo가 마지막 일 필요가있는 이유는 숨겨진 참조가 동기화되지 않도록하는 것입니다.

가비지 수집 관점에서 보면 foo가 최종적으로 없어도 안전합니다. 그러나 foo bar bar에 대한 참조는 bar를 생성 할 때 할당되고 결코 업데이트되지 않습니다. 그래서 foo에 다른 것을 할당하는 것이 허용되면 bar는 여전히 "old"객체를 보게됩니다.

최종 요구 사항은 로컬 변수 및 매개 변수에만 적용되며 포함하는 클래스의 인스턴스 필드에는 적용되지 않습니다.

+0

'foo'가'final' 일 필요가있는 이유에 대해 자세히 설명해 주시겠습니까? 감사합니다 –

+0

익명 클래스 모음에는 foo에 대한 참조가 들어있는 숨겨진 인스턴스 필드 (컴파일러에서 생성됨)가 있습니다. 막대가 작성되면 지정됩니다.foo가 final이 아니라면 포함하는 메서드는 foo를 새 객체에 할당 할 수 있으므로 bar는 잘못된 객체 (이전 객체)를 보게됩니다. – Thilo

+0

로컬 메소드의 변수가 범위를 벗어납니다. 그렇다면 존재하지 않는 변수와의 동기화가 필요한 이유는 무엇입니까? – Pawel

0

안전 할 수 있지만 내부 클래스가 수행중인 작업에 따라 다릅니다.

내부 클래스에서 변수를 사용하는 방법을 고려해야합니다. 예를 들어, 실행 가능 또는 비동기 태스크를 작성하는 경우 내부 클래스는 외부 스레드가 종료 된 후에도 다른 스레드의 변수에 액세스 할 수 있습니다. 따라서 의도하지 않은 문제를 방지하기 위해 개체를 사용하기 전에 개체를 동기화해야 할 수도 있습니다.

또한 변수가 최종해야합니다. 이는 런타임시 내부 클래스가 변수 참조를 변경하지 못하도록하는 언어 제한 사항입니다. 그것은 조금은 고통스럽고 그것이 언어의 명백한 특징이 아니라 암묵적인 것이라면 좋을 것입니다.

0

리플렉션을 통해 클래스 로커를 해킹하지 않는 일반적인 작업을 수행하는 경우 완벽하게 안전합니다. 다른 사람들이 언급했듯이 (내부 클래스가 정적으로 정의되지 않는 한) 내부에서 외부 객체로의 암시 적 참조가 있으므로 가비지 수집되지 않습니다.

일반적으로 에는에 일반적인 참조를 통해 가비지 수집되는 객체에 대한 핸들을 가질 방법이 없습니다. 이것은 당신이 걱정할 필요가없는 것들입니다 (C++이 아닙니다))

유일한 방법은 약한 참조 (작업을 위해 특별히 만들어진 것입니다) 또는 바이트 코드를 사용하는 것입니다. . 하지만 '정상'코드는 아닙니다.

0

코드가 컴파일되지 않으므로 질문이 의미가 없습니다. 필요한 '최종'수정자를 입력하면 코드가 컴파일되고 안전합니다. 이는 '최종'수정자가 전달하는 것입니다.

관련 문제