11

コードの代替(1) が警告なしでコンパイルされ、コードの代替(2) が「チェックされていないキャスト」警告を生成するのはなぜですか?

両方に共通:

class Foo<T> {
    Foo( T [] arg ) {
    }
}

代替案 (1):

class Bar<T> extends Foo<T> {
    protected static final Object [] EMPTY_ARRAY = {};

    @SuppressWarnings("unchecked")
    Bar() {
         super( (T []) EMPTY_ARRAY );
    }
}

代替案 (2):

class Bar<T> extends Foo<T> {
    @SuppressWarnings("unchecked")
    Bar() {
         super( (T []) EMPTY_ARRAY );
    }

    protected static final Object [] EMPTY_ARRAY = {};
}

代替案 (2) は以下を生成します。

javac -Xlint:unchecked Foo.java Bar.java 
Bar.java:4: warning: [unchecked] unchecked cast
             super( (T []) EMPTY_ARRAY );
                           ^
  required: T[]
  found:    Object[]
  where T is a type-variable:
    T extends Object declared in class Bar
1 warning

これは:

java version "1.7.0_07"
Java(TM) SE Runtime Environment (build 1.7.0_07-b10)
Java HotSpot(TM) 64-Bit Server VM (build 23.3-b01, mixed mode)
4

4 に答える 4

4

@SuppressWarnings( JLS 9.6.3.5 ) セクションと未チェックの警告 ( JLS 5.1.9 ) セクションの両方に、この問題につながる可能性のある問題はないようです。私の推測では (SSCE を自分でテストすることなく)、コンパイラにバグが見つかったということです。Oracle にバグ レポートを提出し、レポート リンクを質問に追加することをお勧めします。

つまり、クラス内のメンバーの順序は、警告がどのように処理されるかについて完全に独立している必要があります。チェックされていない警告コードだけのエッジケースである場合もあれば、より大きな問題である場合もあります。

当面は、最初にすべきことを実行することですべての問題を解消し、この質問で概説されているように、既存の配列をキャストする代わりに空の配列を動的に生成できます。

編集

私の場合、リンクされた提案がどのように機能するかわかりませEMPTY_ARRAYstatic final

もう作成しstatic finalないで、コンストラクターに aを指定Class<T>します。

@SuppressWarnings("unchecked") // Still need this
public Bar(Class<T> clazz) {
    super((T[]) Array.newInstance(clazz, 0));
}

finalJava は、デッド コードの場合を除いて、変数の値を警告に使用することはほとんどありません。そうしないと、次のようなエッジ ケースが発生します。

class Bar<T> extends Foo<T> {
    // Is it really empty?
    protected static final Object [] EMPTY_ARRAY = SomeOtherClass.getEmptyArray();

    @SuppressWarnings("unchecked")
    Bar() {
         super( (T []) EMPTY_ARRAY );
    }
}

そのロジックをコンパイラに書き込む必要があります。「空の配列」のような特殊なケースでは不要な複雑化です。さらに、このようなキャストは、結局すべてコードの匂いです。

その答え以外にあるかもしれない別のオプションは、var args を使用することです。Foo:

class Foo<T> {
    Foo( T ... arg ) {
    }
}

そしてBar

class Bar<T> extends Foo<T> {

    Bar() {
         super();
    }
}

それはうまくいくはずで、すべてのキャスト、空の配列、警告などを排除します。 var args とその呼び出しの詳細については、こちら を参照してください

于 2012-12-11T22:46:33.000 に答える
3

Windows 7 64b マシンでこの奇妙な動作を次のようにエミュレートできます。

  • Java(TM) SE Runtime Environment (build 1.7.0_02-b13)
  • OpenJDK Runtime Environment (build 1.8.0-ea-lambda-nightly-h1669-20121030-b63-b00)

つまり、 OpenJDKOracle JDKの両方、つまりJDK7JDK8の両方が影響を受けます (はい、既にダウンロードできます)。

Eclipse は独自の JDT コンパイラを使用しているため、この問題はありません。

したがって、これは実際にはjavacバグのようです。報告する場合は、最新情報をお知らせください。

編集:

また、コンピューターにJDK6のインストールを見つけたので、それを試してみましたが、実際には、どちらの場合も警告なしで動作します。これは正しい動作です:

  • Java(TM) SE Runtime Environment (build 1.6.0_23-b05)

私の Windows は 64b ですが、上記の JDK はすべて 32b しかありません。

于 2012-12-11T23:38:55.323 に答える
1

この簡略化されたセットアップで動作を再現することができました。

class Bar<T> {
   @SuppressWarnings("unchecked")
   Bar() {
      T[]dummy = (T[]) EMPTY_ARRAY;
   }

   private static final Object [] EMPTY_ARRAY = {};
}

ブライアンが示唆したように、それはコンパイラのバグのようです。さらに、この動作は配列に制限されています。EMPTY_ARRAYをに置き換えてにObjectキャストしてもT、期待どおりに警告は発行されません。

java version "1.7.0_09"
Java(TM) SE Runtime Environment (build 1.7.0_09-b05)
Java HotSpot(TM) 64-Bit Server VM (build 23.5-b02, mixed mode)
于 2012-12-11T23:22:44.110 に答える
1

これは、Oracle と OpenJDK 7 および 8 の両方のバグです。

クラス内の宣言の並べ替えからコンパイルの警告/エラーを取得することはできません (すべきではありません)。

実行時エラー、はい。コンパイラ エラー、いいえ。

これはバグ 8016636 ですが(提出していただきありがとうございます)、1 年以上活動がありません。

残念ながら、これは Oracle のバグ トラッカーでは珍しいことではありません。


追加の奇妙さ:

  • EMPTY_ARRAYでない場合、警告は抑制されfinalます。

  • 皮肉なことに、配列以外で初期化すると、警告は抑制されますObject EMPTY_ARRAY = new Object()。(でもそんなことしないで…)

于 2014-08-23T18:50:22.513 に答える