2009-05-28 2 views
45

제 동료는 Eclipse 코드 포맷 및 경고 설정 중 일부를 더욱 엄격하게 만들 것을 제안했습니다. 이러한 변경 사항의 대부분은 의미가 있지만 자바에서이 이상한 경고를받습니다. "문제"를 재현 할 수있는 몇 가지 테스트 코드는 다음과 같습니다.자바의 개인 정적 중첩 클래스에 대한 합성 접근에 대한 Eclipse 경고?

package com.example.bugs; 

public class WeirdInnerClassJavaWarning { 
    private static class InnerClass 
    { 
     public void doSomething() {} 
    } 

    final private InnerClass anInstance; 

    { 
     this.anInstance = new InnerClass(); // !!! 
     this.anInstance.doSomething(); 
    } 
} 
// using "this.anInstance" instead of "anInstance" prevents another warning, 
// Unqualified access to the field WeirdInnerClassJavaWarning.anInstance  

줄이 !!!

액세스 생성자 WeirdInnerClassJavaWarning.InnerClass()를 는 합성 접근 방법으로 에뮬레이트 둘러싸에 : 나에게 나의 새로운 경고 설정 Eclipse에서이 경고를 제공합니다. 가시성을 높이면 실적이 향상됩니다.

이것은 무엇을 의미합니까? "개인 정적 클래스"를 "보호 된 정적 클래스"로 변경하면 경고 메시지가 사라지고 나에게는 의미가 없습니다.


편집 : 나는 마지막으로 "올바른"수정을 파악. 여기에서 진짜 문제는이 중첩 된 개인 정적 클래스에 공용 생성자가 누락 된 것 같습니다. 즉, 하나의 팅겨 경고 제거 :

package com.example.bugs; 

public class WeirdInnerClassJavaWarning { 
    private static class InnerClass 
    { 
     public void doSomething() {} 
     public InnerClass() {} 
    } 

    final private InnerClass anInstance; 

    { 
     this.anInstance = new InnerClass(); 
     this.anInstance.doSomething(); 
    } 
} 

내가 클래스가 개인 중첩 클래스 (그래서 다른 클래스가 둘러싸는 클래스의 서브 클래스를 포함하여, 그것을 액세스 할 수 없습니다 수)되고 싶어하고 나는 그것이 고정되고 싶어 수업.

중첩 된 클래스를 개인용이 아닌 보호하는 것이 왜 "문제"를 수정하는 또 다른 방법인지 이해할 수 없지만 Eclipse의 버크/버그 일 수 있습니다.

(사과, 나는 더 명확하게 할 NestedClass 대신 InnerClass의 부르심을해야합니다.)

답변

41

다음과 같이 경고를 제거 할 수 있습니다

다른 사람이 말했듯이
package com.example.bugs; 

public class WeirdInnerClassJavaWarning { 
    private static class InnerClass { 
     protected InnerClass() {} // This constructor makes the warning go away 
     public void doSomething() {} 
    } 

    final private InnerClass anInstance; 
    { 
     this.anInstance = new InnerClass(); 
     this.anInstance.doSomething(); 
    } 
} 

명시적인 생성자가있는 전용 클래스가 외부에서 인스턴스화 할 수 없기 때문에, 이클립스 합성 방법을 통해 제외하고, 불평 그 Java 컴파일러가 생성됩니다.당신은 당신의 코드를 가지고가는 경우에, 컴파일, 다음, 당신은 (포맷) 다음 얻을 jad (*)로 디 컴파일 :

public class Test { 
    private static class InnerClass { 
    public void doSomething() {} 
    // DEFAULT CONSTRUCTOR GENERATED BY COMPILER: 
    private InnerClass() {} 

    // SYNTHETIC METHOD GENERATED BY THE JAVA COMPILER:  
    InnerClass(InnerClass innerclass) { 
     this(); 
    } 
    } 

    public Test() { 
    anInstance.doSomething(); 
    } 

    // Your instance initialization as modified by the compiler: 
    private final InnerClass anInstance = new InnerClass(null); 
} 

당신이 보호 된 생성자를 추가하는 경우, 합성 코드가 필요하지 않습니다. 합성 코드는 이론적으로 공공 또는 보호 된 생성자를 사용하는 비 합성 코드보다 느린 것으로 추측됩니다.

(*) jad의 경우 위키 피 디아 페이지에 연결되었습니다 ...이 프로그램을 호스팅 한 도메인은 만료되었지만 Wikipedia는 내가 직접 테스트하지 않은 다른 도메인으로 연결됩니다. 나는 다른 (아마도 더 최근의) 디 컴파일러가 있다는 것을 알고 있지만 이것은 내가 사용하기 시작한 것입니다. 참고 : 은 최신 Java 클래스 파일을 디 컴파일 할 때이라고 불평하지만 여전히 좋은 결과를 보여줍니다. 개인보다는 보호 중첩 된 클래스를 만드는 이유를 난 아직도 이해가 안

+0

편집하기 전에 게시하는 중이라고 가정합니다. 어쨌든 이것은 올바른 대답 인 것처럼 보입니다. –

+0

예, 당신과 나는 동시에 타이핑을하고있었습니다. 나는 Eclipse 경고를받는 이유를 설명하기 위해 나의 대답을 확장했다. – Eddie

+0

+1 디 컴파일러에 대해, 나는 그런 것들이 있다는 것을 결코 알지 못했다.이 경고의 텍스트를 변경해야한다는 것을 Eclipse 용 버그를 제출해야하는 것처럼 들리므로이 경고의 의미와 해결 방법을 조금 더 분명하게 알 수 있습니다. –

8

당신은 WeirdInnerClassJavaWarning에서 InnerClass을 인스턴스화 할 수 없습니다. 그것은 비공식적인데, JVM은 당신을 그렇게하지 않을 것이지만, 자바 언어는 (어떤 이유로) 그렇게 할 것이다.

따라서 javac은 InnerClass에서 새로운 InnerClass()를 반환하는 추가 메서드를 만들므로 WeirdInnerClassJavaWarning에서 InnerClass 인스턴스를 만들 수 있습니다.

나는 perfomance 강하가 미미할 수 있기 때문에 정말로 제거 할 필요가 없다고 생각합니다. 그러나 정말로 원한다면 할 수 있습니다.

+2

+1 성능 향상은 현대 JVM에서 완전히 중요하지 않습니다. 이클립스는 여기에 지나치게 열광적이다. 나는 경고를 완전히 꺼버릴 것이다. – skaffman

+0

"WeirdInnerClassJavaWarning에서 InnerClass를 인스턴스화 할 수 없습니다. 비공개이므로 JVM은 사용자를 허용하지 않지만 Java 언어는 (어떤 이유로) 그렇게 할 것입니다." 생성자가 없으며 Java 언어가 자동으로 arg가없는 public 생성자를 생성합니다. 아무도 존재하지 않습니다. 이 마법은 Eclipse가 경고 한 것입니다. – Powerlord

+1

이 생성자는 private 내부 클래스의 경우 private이 될 것입니다. 그렇지 않으면이 경고는 의미가 없습니다. – alamar

0

대신 개인 또는 보호의 기본 범위를 사용하여 제거하는 수 있어야, 즉

static class InnerClass ... 

또한 내이 경고 코드의 줄에 커서를 배치하는 것을주의 가치와 ctrl-1을 누르면 Eclipse가 자동으로이 문제를 해결할 수 있습니다.

+0

감사하지만 나는 그것을 원하지 않는다. 그것은 둘러싸는 클래스 이외의 클래스에서는 보이지 않아야한다. –

+1

Eclipse의 성능 지향 경고가 사용자의 필요와 관련이 없으므로이 경우 경고를 표시하지 않을 수 있습니다. – izb

+0

관련 설정이 "액세스 할 수없는 동봉 된 멤버에게 액세스" – akauppi

3

는 "문제"를 해결하는 또 다른 방법입니다,하지만 어쩌면 그

이클립스

의 특질/버그입니다

Eclipse의 버크/버그는 아니며 Java의 기능입니다. Java Language Specification, 8.8.9는 말한다 : 클래스가 보호 선언 된 경우

..., 디폴트 생성자는 암시 적으로 보호 된 액세스 한정자가 주어집니다 ...

그런데
+0

... protected 및 private은 클래스를 둘러 쌀 때 다른 의미가 있습니까? 유일한 차이점은 액세스가 * 서브 클래스 *에 부여되는 방법이라고 생각했습니다. –

+1

소스 코드 수준 (컴파일러)에는 영향을 미치지 않지만 바이트 코드 수준 (가상 컴퓨터)에서는 의미가 없습니다. 내가 아는 한 JVM은 중첩 클래스를 알지 못하므로 그 대신에 .class 파일을 추가로 확보해야합니다. 컴파일러는 "외부"클래스가 중첩 클래스의 개인 멤버에 액세스 할 수 있도록 (런타임에) 합성 메서드를 만들어야합니다. (BTW : protected는 패키지 접근을 포함하고있어서 경고를 피하기에 충분하다.) (BTW2 : JLS에 정의 된대로 정적 중첩 클래스는 내부 클래스가 아니다 ...) –

19

, 설정이 경고를 설정하는 오프 "코드 스타일"에서 자바 오류/경고 페이지에 있고 호출됩니다 바깥 쪽 형식의 액세스 할 수없는 멤버에

액세스

+1

이미 나를 위해 무시하도록 설정되었지만 여전히 경고가 표시됩니다. 아마도 Juno에서 뭔가가 변경되었을 것입니다. –

+0

프로젝트 별 설정에서 경고로 설정할 수 있습니까? – robinst

+0

나는 이것이 얼마나 비참한 지 알지만, 경고가 지속되면 어딘가에 문자를 추가하고 파일을 저장하십시오. 나중에 경고가 사라질 것입니다. – Blauhirn

2

여기 당신이

javac -XD-printflat WeirdInnerClassJavaWarning.java -d tmp 

원시 출력 질문에 원래의 클래스 코드를 사용하는 경우 얻을 수있는 것입니다, 여러분을 돕기 위해, 컴파일러는 주석을 덧붙였다. synthetic 패키지 private 클래스와 생성자를 추가합니다.

public class WeirdInnerClassJavaWarning { 
    { 
    } 

    public WeirdInnerClassJavaWarning() { 
     super(); 
    } 
    { 
    } 
    private final WeirdInnerClassJavaWarning$InnerClass anInstance; 
    { 
     this.anInstance = new WeirdInnerClassJavaWarning$InnerClass(null); 
     this.anInstance.doSomething(); 
    } 
} 

class WeirdInnerClassJavaWarning$InnerClass { 

    /*synthetic*/ WeirdInnerClassJavaWarning$InnerClass(WeirdInnerClassJavaWarning$1 x0) { 
     this(); 
    } 

    private WeirdInnerClassJavaWarning$InnerClass() { 
     super(); 
    } 

    public void doSomething() { 
    } 
} 

/*synthetic*/ class WeirdInnerClassJavaWarning$1 { 
} 
관련 문제