Javaジェネリックのオラクルのトレイルの1つである「Effects of Type Erasure and Bridge Methods」を検討していましたが、私は説明を納得させることができませんでした。不思議なことに、コードをローカルでテストしたところ、トレイルが説明する動作を再現することさえできませんでした。ここに関連するコードは次のとおりです。Javaジェネリックに関するOracleのトレールの潜在的な問題
public class Node<T> {
public T data;
public Node(T data) { this.data = data; }
public void setData(T data) {
System.out.println("Node.setData");
this.data = data;
}
}
public class MyNode extends Node<Integer> {
public MyNode(Integer data) { super(data); }
public void setData(Integer data) {
System.out.println("MyNode.setData");
super.setData(data);
}
}
オラクル・トレイルは、このコードスニペットのために次の動作を主張する:
MyNode mn = new MyNode(5);
Node n = mn; // A raw type - compiler throws an unchecked warning
n.setData("Hello");
Integer x = mn.data; // Causes a ClassCastException to be thrown.
このコードスニペットは、型消去した後、次のようになります。
MyNode mn = new MyNode(5);
Node n = (MyNode)mn; // A raw type - compiler throws an unchecked warning
n.setData("Hello");
Integer x = (String)mn.data; // Causes a ClassCastException to be thrown.
ここで使われているキャストやその動作を理解できませんでした。
MyNode mn = new MyNode(5);
Node n = mn; // A raw type - compiler throws an unchecked warning
n.setData("Hello"); // Causes a ClassCastException to be thrown.
Integer x = mn.data;
言い換えれば、JVMはString
がsetData()
で使用することを許可しません。私はローカルのJava 7でIntelliJのを使用してこのコードを実行しようとしたとき、私はこの動作を得ました。これは私には直感的なことであり、ジェネリックの理解に同意します。 MyNode
mn
はInteger
で作成されているため、setData()
の呼び出しをすべてInteger
にキャストして、型の安全性を確保する必要があります(Integer
が渡されています)。
Oracleトレイルのこの明白なバグについて、誰かが何かを明らかにすることはできますか?
私はそれをあまりにも多くのクレジットを与えているページがその言語に緩んでいると言っ思う:あなたは
MyNode.class
ファイルにjavap -p
を実行する場合、あなたがその実際に参照してくださいよ、それは2つの
setData
メソッドを持っています。つまり、n.setData( "Hello")という呼び出しは、実際にはコンパイラによって生成されたブリッジメソッドに当たっていて、スーパーメソッドを呼び出す前に渡されるすべてのオブジェクトを 'Integer'にキャストします。まあ、これは私が推測するすべてのことを、洞察力のおかげで説明します。 –私は悪いドキュメントについて嫌になる傾向がありますが、私は恐ろしいドキュメント、特にAPIの出版に慣れ親しんできました。皮肉なことに、若い頃Javaには最高のドキュメントがいくつかありました。今日...私は自分自身に私の軽蔑を維持しようとする。 – Adam