質問

以下のコードでClassCastExceptionがどのような状況で発生するかは次のとおりです。

import java.util.Arrays;
import java.util.List;

public class Generics {

    static List getObjects() {
        return Arrays.asList(1, 2, 3);
    }

    public static void main(String[] args) {
        List<String> list = getObjects();
        for (Object o : list) { // ClassCastException?
            System.out.println(o);
        }
    }
}

私たちは生産環境で同様のケースを持っていました(悪い練習、私は知っています)、顧客はコメントでClassCastExceptionでログを提供しましたが、私はそれを再現することはできません。何かご意見は?

JVMは、Foreachを使用するときにバックグラウンドでイテレーターを作成することを知っていますが、場合によっては生のイテレーターを作成し、他の場合にパラメータ化されたものを作成できますか?

アップデート:また、JDK 1.6.0_21-B07を使用して、生成されたバイトコードとWindowsでも見ていました チェックキャスト 作られた。面白い :)

主な方法は次のとおりです。

public static void main(java.lang.String[]);
  Code:
   0:   invokestatic    #34; //Method getObjects:()Ljava/util/List;
   3:   astore_1
   4:   aload_1
   5:   invokeinterface #36,  1; //InterfaceMethod java/util/List.iterator:()Ljava/util/Iterator;
   10:  astore_3
   11:  goto    28
   14:  aload_3
   15:  invokeinterface #42,  1; //InterfaceMethod java/util/Iterator.next:()Ljava/lang/Object;
   20:  astore_2
   21:  getstatic   #48; //Field java/lang/System.out:Ljava/io/PrintStream;
   24:  aload_2
   25:  invokevirtual   #54; //Method java/io/PrintStream.println:(Ljava/lang/Object;)V
   28:  aload_3
   29:  invokeinterface #60,  1; //InterfaceMethod java/util/Iterator.hasNext:()Z
   34:  ifne    14
   37:  return

答えをありがとう!

更新2: :私はそれを使用するEclipse IDEで誤解を招きました 独自のコンパイラ したがって、実際には上のバイトコードは、 Eclipseコンパイラ. 。見て ここ Eclipseでコードを手動でコンパイルする方法。結論として、Eclipseコンパイラは、プラットフォームに関係なく、Sunコンパイラから異なるバイトコードを生成します。ここで説明するケースは1つです。

役に立ちましたか?

解決

そのコードはすべきではありません いつも 投げる ClassCastException? Sun Java 6コンパイラとランタイム(Linuxで)を使用しています。あなたはキャストしています Integers as Strings。作成されたイテレーターはanになります Iterator<String>, 、しかし、それは最初の要素にアクセスしようとします。 Integer, 、そして失敗します。

アレイを次のように変更すると、これは明確になります。

return Arrays.asList("one", 2, 3);

最初の要素は String そして、出力が見えます。そうして Iterator<String> 文字列ではないため、2番目のもので失敗します。

ジェネリックを使用するだけでコードが機能します List 特定のものの代わりに:

List list = getObjects();
for (Object o : list) {
    System.out.println(o);
}

...または、もちろん、使用する場合 List<Integer>, 、内容はあるので Integers。あなたが今していることは、コンパイラ警告をトリガーします - Note: Generics.java uses unchecked or unsafe operations.- そして正当な理由があります。

この変更も機能します。

for (Object o : (List)list)

...おそらくその時点であなたは Iterator, 、ではありません Iterator<String>.

Bozhoは、Windows XPでこのエラーが表示されないと言っています(どのコンパイラとランタイムを言及していませんが、Sunを推測しています)、そしてあなたはそれを見ていない(または確実ではない)ので、明らかにいくつかがあります実装の感度はここにありますが、最終的な行は次のとおりです。 List<String> と対話する ListIntegers。 :-)

これが私がコンパイルしているファイルです:

import java.util.Arrays;
import java.util.List;

public class Generics {

    static List getObjects() {
        return Arrays.asList("one", 2, 3);
    }

    public static void main(String[] args) {
        List<String> list = getObjects();
        for (Object o : list) { // ClassCastException?
            System.out.println(o);
        }
    }
}

これが編集です:

tjc@forge:~/temp$ javac Generics.java 
Note: Generics.java uses unchecked or unsafe operations.
Note: Recompile with -Xlint:unchecked for details.

これが実行です:

tjc@forge:~/temp$ java Generics 
one
Exception in thread "main" java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.String
    at Generics.main(Generics.java:12)

12行目は次のとおりです for 声明。それが私がそれを変更したので、それが最初の要素を出力したことに注意してください String. 。他の人には出力されませんでした。 (そして、私がその変更を行う前に、すぐに失敗しました。)

これが私が使用しているコンパイラです:

tjc@forge:~/temp$ which javac
/usr/bin/javac
tjc@forge:~/temp$ ll /usr/bin/javac
lrwxrwxrwx 1 root root 23 2010-09-30 16:37 /usr/bin/javac -> /etc/alternatives/javac*
tjc@forge:~/temp$ ll /etc/alternatives/javac
lrwxrwxrwx 1 root root 33 2010-09-30 16:37 /etc/alternatives/javac -> /usr/lib/jvm/java-6-sun/bin/javac*

これが分解です checkcast:

tjc@forge:~/temp$ javap -c Generics
Compiled from "Generics.java"
public class Generics extends java.lang.Object{
public Generics();
  Code:
   0:   aload_0
   1:   invokespecial   #1; //Method java/lang/Object."":()V
   4:   return

static java.util.List getObjects();
  Code:
   0:   iconst_3
   1:   anewarray   #2; //class java/io/Serializable
   4:   dup
   5:   iconst_0
   6:   ldc #3; //String one
   8:   aastore
   9:   dup
   10:  iconst_1
   11:  iconst_2
   12:  invokestatic    #4; //Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
   15:  aastore
   16:  dup
   17:  iconst_2
   18:  iconst_3
   19:  invokestatic    #4; //Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
   22:  aastore
   23:  invokestatic    #5; //Method java/util/Arrays.asList:([Ljava/lang/Object;)Ljava/util/List;
   26:  areturn

public static void main(java.lang.String[]);
  Code:
   0:   invokestatic    #6; //Method getObjects:()Ljava/util/List;
   3:   astore_1
   4:   aload_1
   5:   invokeinterface #7,  1; //InterfaceMethod java/util/List.iterator:()Ljava/util/Iterator;
   10:  astore_2
   11:  aload_2
   12:  invokeinterface #8,  1; //InterfaceMethod java/util/Iterator.hasNext:()Z
   17:  ifeq    40
   20:  aload_2
   21:  invokeinterface #9,  1; //InterfaceMethod java/util/Iterator.next:()Ljava/lang/Object;
   26:  checkcast   #10; //class java/lang/String
   29:  astore_3
   30:  getstatic   #11; //Field java/lang/System.out:Ljava/io/PrintStream;
   33:  aload_3
   34:  invokevirtual   #12; //Method java/io/PrintStream.println:(Ljava/lang/Object;)V
   37:  goto    11
   40:  return

}

繰り返しになりますが、一番下の行は次のとおりです。 List<String> と対話する List そうでないものが含まれています Strings。 :-)

他のヒント

私もそれを再現することはできませんが、私は修正する必要がある次の間違いを見つけます:

  • 作る getObjects() 戻る List<Integer>, 、生のタイプではなく
  • 期待しないでください List<String>, 、しかしa List<Integer> 代わりは
  • 反復するとき、ループ for (Integer o : list)

問題は方法です static List getObjects() { 汎用(パラメーターではない)を返します List. 。そして、あなたはそれを割り当てます List<String>. 。この行はコンパイラ警告を与えるはずであり、それは問題を示唆しているはずです。

この部分 :

List<String> list = getObjects();
for (Object o : list) { // ClassCastException?
    System.out.println(o);
}

として簡素化されます

List<String> list = getObjects();
for (Iterator<String> iterator = list.iterator(); iterator.hasNext();) {
    Object o = iterator.next();
    System.out.println(o);
}

しかし、イテレーターの実装は、電話をかけるときにキャストしようとします next() メソッドコンテンツが送信します IteratorString.

だからあなたはCCEを持っています。

ソリューション:

どこでもジェネリックを使用するか、使用しないでくださいが、一貫性を持つことは本当に重要です。あなたが返した場合 List<Integer> またはa List<? super Integer> 編集時にこの問題を見たでしょう。

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top