50

私の同僚は、Eclipseのコードフォーマットと警告の設定のいくつかをより厳密にすることを提案しました。これらの変更の大部分は理にかなっていますが、Javaでこの1つの奇妙な警告が表示されます。「問題」を再現するためのテストコードは次のとおりです。

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    

!!!とのライン 新しい警告設定を使用して、Eclipseでこの警告が表示されます。

囲んでいるコンストラクターWeirdInnerClassJavaWarning.InnerClass()へのアクセスは、合成アクセサーメソッドによってエミュレートされます。可視性を高めると、パフォーマンスが向上します。

これは何を意味するのでしょうか?「プライベート静的クラス」を「保護された静的クラス」に変更すると、警告が消えます。これは私には意味がありません。


編集:私はついに「正しい」修正を見つけました。ここでの本当の問題は、このネストされたプライベート静的クラスにパブリックコンストラクターがないことです。その1つの調整により、警告が削除されました。

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の癖/バグかもしれません。

(申し訳ありませんが、より明確にするために、InnerClassではなくNestedClassと呼ぶべきでした。)

4

6 に答える 6

45

次のようにして、警告を取り除くことができます。

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 コンパイラーが作成する合成メソッドを介する場合を除き、外部からインスタンス化できないため、Eclipse は不平を言っています。コードを取得してコンパイルし、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 については、ウィキペディアのページにリンクしました ... このプログラムをホストしていたドメインの有効期限が切れていますが、ウィキペディアは私がテストしていない別のページにリンクしています。他にも(おそらくもっと最近の)逆コンパイラがあることは知っていますが、これは私が使い始めたものです。注:最近の Java クラス ファイルを逆コンパイルすると問題が発生しますが、それでも問題なく動作します。

于 2009-05-28T14:37:32.013 に答える
21

ちなみに、警告をオフにする設定は、「コードスタイル」の下のJavaエラー/警告ページにあり、次のように呼び出されます。

囲んでいる型のアクセスできないメンバーへのアクセス

于 2011-08-30T17:27:09.653 に答える
9

WeirdInnerClassJavaWarningからInnerClassをインスタンス化することはできません。これはプライベートであり、JVMでは許可されませんが、Java言語(何らかの理由で)では許可されます。

したがって、javacは、新しいInnerClass()を返すだけの追加のメソッドをInnerClassに作成します。これにより、WeirdInnerClassJavaWarningからInnerClassインスタンスを作成できます。

パフォーマンスの低下は計り知れないほど小さいので、本当にそれを取り除く必要はないと思います。ただし、本当に必要な場合は可能です。

于 2009-05-28T14:11:26.433 に答える
4

ネストされたクラスをプライベートではなく保護することが「問題」を修正する別の方法である理由はまだわかりませんが、それはEclipseの癖/バグかもしれません

これはEclipseの癖やバグではなく、Javaの機能にすぎません。Java言語仕様、8.8.9は、次のように述べています。

...クラスが保護されていると宣言されている場合、デフォルトのコンストラクターには暗黙的にアクセス修飾子が保護されています...

于 2009-05-28T14:52:36.617 に答える
3

人々を助けるために、質問で元のクラスコードを使用すると得られるものは次のとおりです

javac -XD-printflat WeirdInnerClassJavaWarning.java -d tmp

生の出力、コンパイラがコメントを追加しました。合成パッケージのプライベート クラスとコンストラクターが追加されていることに注意してください。

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 {
}
于 2013-08-21T15:27:12.177 に答える
0

private または protected の代わりにデフォルトのスコープを使用することで、それを取り除くことができるはずです。

static class InnerClass ...

また、警告のあるコード行にカーソルを置き、ctrl-1 を押すと、Eclipse がこれを自動的に修正できる可能性があることにも注意してください。

于 2009-05-28T14:19:49.647 に答える