2009-09-29 6 views
4

내가 가지고있는 다음 코드 : -인스턴스 이니셜 대 개인 회원

public class Test5 { 
    private int value ; 
    public static void main(String[] args) { 
     Test5 a, b; 
     a = new Test5(); 
     b = new Test5(){{ value = 1 ;}}; 
    } 
} 

다음 줄에 오류가 표시됩니다 : -

b = new Test5(){{ value = 1 ;}}; 

비 정적 변수가 정적 문맥에서 참조 할 수 없습니다.

이중 중괄호 관용구는 두 번째 중괄호가 익명 클래스의 인스턴스 초기화 프로그램임을 나타냅니다. 그렇다면 private 멤버 변수를 초기화 할 수없는 이유는 무엇입니까?

답변

5

라인

b = new Test5(){{ value = 1 ;}}; 

Test5를 확장 익명 클래스의 인스턴스를 만듭니다. 그러나 value은 비공개이므로 익명 클래스는 수퍼 클래스의 인스턴스 변수에 액세스 할 수 없습니다.

의 익명 하위 클래스에 표시되는 value이라는 변수가 없으므로 컴파일러는 다음 범위에서 대체를 찾습니다. 이 경우 다음 범위는 정적 main 메서드에 속합니다. 컴파일러는 인스턴스 변수 Test5을 검색하고 인스턴스 변수를 정적 컨텍스트에서 참조 할 수 없으므로 경고를 표시합니다.

당신은 여기에 두 가지 대안이 있습니다

  1. 어느 익명 클래스 인스턴스 변수에 액세스 할 수 있도록 : 보호 int 값을;

  2. 또는 정적 main 방법에 액세스 할 수 있도록 변수 : 전용 정적 int 값;

첫 번째 대안은 실제로하고 싶은 것입니다.

@Tom : 문제는 이 아니며입니다. 먼저 정적 범위가 검색됩니다. 이 경우 인스턴스 변수 value이 여전히 먼저 발견되어 여전히 참조 할 수 없으므로 대체 (1)이 작동하지 않습니다.

@Ken : 귀하의 instanceMethod()은 원하지 않는 것입니다! 다음 코드를 살펴보십시오.

class Test5A { 
    private int value; 

    public void instanceMethod() { 
     Test5A a = new Test5A() {{ value = 1; }}; // (A) 
     System.out.println(this.value); 
     System.out.println(a.value); 
    } 

    public static void main(String[] args) { 
     new Test5A().instanceMethod(); 
    } 
} 

이 예제 코드는 클래스의 동작을 모방 한 것입니다. 컴파일하고 실행하면 출력이 "1 0"임을 알 수 있습니다.

(A)의 익명 하위 클래스의 인스턴스 초기화 프로그램이 인스턴스 변수 인 value에 할당하는 것처럼 보이지만 실제로는 해당 변수는 익명 클래스의 수퍼 클래스에서만 볼 수 있습니다. 대신 라인 (A)에서 value이라는 유일한 표시 변수는 instanceMethod()이 호출되는 Test5A 인스턴스의 인스턴스 변수입니다.따라서 하나로 변경됩니다.

이제 value의 가시성을 증가하자

class Test5B { 
    protected int value; 

    public void instanceMethod() { 
     Test5B a = new Test5B() {{ value = 1; }}; 
     System.out.println(this.value); 
     System.out.println(a.value); 
    } 

    public static void main(String[] args) { 
     new Test5B().instanceMethod(); 
    } 
} 

출력이이 시간을 "0 1". 인스턴스 변수 value은 익명 하위 클래스에 의해 상속 된이고 은 해당 인스턴스 이니셜 라이저에 표시되는입니다. 따라서 올바른 인스턴스 변수에 할당됩니다.

+1

아니요, 실제로 액세스 할 수 있습니다. javac는 액세스 변경자가 아닌 정적 컨텍스트 인 것으로 오류를보고합니다. –

+0

Tom이 맞습니다! 값을 액세스 할 수 있습니다 .. 그리고 언급 한 바와 같이 정적 문제는 오류로보고되고! – Ajay

+2

"private"대신 "protected"값을 지정하면 Ajay의 예는 경고를 전혀 표시하지 않습니다. 즉 문제는 익명의 클래스가 변수를 볼 수 없으며 컴파일러는 정적이 아닌 변수가 main의 컨텍스트에서 액세스되어야한다고 생각한다는 것입니다. – janko

1

원본 Test5 클래스에 속한 값 값 필드를 설정하려고 했으므로이 클래스의 인스턴스를 정적 ​​컨텍스트에서 사용할 수 없습니다. 당신은 당신이 this.value 그것을 참조해야합니다 익명 클래스의 값을 설정하려면

public class Test5 { 
    private int value = 0; 
    public static void main(String[] args) { 
     (new Test5()).foo(); 
    } 
    void foo(){ 
     Test5 b = new Test5(){ 

      { 
       value = 1; 
      } 

     }; 
     System.out.println(value); 
    } 
} 

출력이 1이 될 것이다 다음 코드를 고려하지만, 값이 개인이기 때문에이 또한 당신에게 컴파일 오류를 줄 것이다.

1

차이점은 인스턴스 컨텍스트 내에서 정적 컨텍스트와는 달리 익명 서브 클래스를 만드는 것입니다. 비교 :

public class InnerClasses { 
    int pack; 
    private int priv; 
    static private int stat; 

    private class NotStatic { 
    { 
     pack = 1; 
     priv = 1; 
     stat = 1; 
    } 
    } 

    private static class IsStatic { 
    { 
     pack = 1; // Static member class not tied to outer instance 
     priv = 1; // Ditto 
     stat = 1; 
    } 
    } 

    public void instanceMethod() { 
    InnerClasses a = new InnerClasses() { 
     { 
     pack = 1; 
     priv = 1; 
     stat = 1; 
     } 
    }; 
    } 

    public static void main(String[] args) { 
    InnerClasses s = new InnerClasses() { 
     { 
     pack = 1; 
     priv = 1; // Anonymous subclass in static context 
     stat = 1; 
     } 
    }; 
    } 

} 

주석이있는 줄은 컴파일되지 않습니다. IsStatic의 내용은 이해하기 쉽지만, instanceMethod의 익명 클래스와 정적 인 main의 차이점은 더 미묘합니다.

private에는 실제로 "해당 최상위 클래스에서 볼 수있는"효과가 있으며 "해당 클래스 내에서만 볼 수있는"효과가 없습니다. (필자가 기억 하듯이, 후자는 JVM 레벨에서의 실제 메커니즘이며, 이전의 효과를 얻는 방법은 접근 자 메서드를 합성하는 것입니다.) 이것이 바로 NotStaticpriv에 액세스 할 수있는 방법입니다.

분명히 차이점은 정적 컨텍스트에서 익명 하위 클래스를 만들 때 "닫힌"것으로 간주되지 않는다는 점입니다. JLS에 더 익숙한 사람이 명확히 할 수 있습니다.

+0

예, instanceMethod()의 익명 클래스가 priv 인스턴스 변수를 참조 할 수 있습니다. 그러나 변수가 아니라 참조 할 것으로 기대할 수 있습니다. 내 확장 대답을 한번보세요. – janko

관련 문제