2013-06-13 5 views
6

私は驚きましたが、...これはコンパイルされます。ここではJava:具体的なパラメータ化された型のnull以外の配列への参照を持つことができるのはなぜですか?

public <T extends Database> ColMetaData<T>[] getTableColumnsAsEnums() { 
      Class<? extends ColMetaData> cls = this.columnsEnumToken(); 
      return cls.<ColMetaData<T>[]>getEnumConstants(); } 

はcolumnsEnumTokenするための方法である:

// Returns a class token for an enum class 
public Class<? extends ColMetaData> columnsEnumToken() { 
    return this.e_colsToken; 
} 

(私は下の2番目の行はコンパイルされませんなぜ私が見ることができますね)

いくつかの質問:

  • は、このメソッド「タイプです安全"?

  • なぜ、この行のコンパイルを行います。

    Class<? extends ColMetaData> cls = this.columnsEnumToken();

    をしかし、この1つはので、互換性のない型のコンパイルに失敗します。

    Class<? extends ColMetaData<T>> cls = this.columnsEnumToken();

  • なぜそれが復帰する方法getTableColumnsAsEnums()ための法的です具体的なパラメータ化された型の配列ColMetaData<T>[]私はこれらが厳密に動詞であると思っていました。なぜなら、それらを安全に操作するランタイム方法がなかったからです。

+1

'cls。 []> getEnumConstants()' inはそれ自体が一般的なメソッドではないのでコンパイルしないでください。 –

+0

最初の箇条書きに答えるには十分な情報がありません: 'columnsEnumToken()'とは何ですか?互換性のない型のエラーメッセージとは何ですか? –

+0

ええ、それは 'return'ステートメントの山括弧に入れたいクラスを置くことができ、うまくいくようです。おそらく、エラーを報告するはずですが、タイプ情報は単に無視されるようです。 – scottb

答えて

2

クラス

理論的には、クラスはパラメータ化された型を表すことができません。たとえば、List<String>のクラスはないので、Class<List<String>>と書くべきではなく、Class<List>と書くべきです。

Class<? extends List<String>>は意味があります。例えば、我々が持っている場合

public class MyStringList extends ArrayList<String>{} 

MyStringList.classは、ジェネリック配列型と間違って何もない

が、それはJavaがいずれかをインスタンス化するために私たちを禁じていることだけだClass<? extends List<String>>

ジェネリックアレイにあるClass<MyStringList>ですしかし、その理由はあまり説得力がありません。あなたが安全であることを知っている限り、キャストを通して1つだけ作成して作成することができます。

実際には、ジェネリックアレイを作成するための簡単な方法があります。 varargsがX...のメソッドを呼び出すと、X[]オブジェクトが作成されます.Xは任意のタイプにできます。

代入互換性

どうやらいくつかの後方互換性の理由のために、我々はList[]List<String>[]に割り当てることができます。そのため返品タイプがColMetaData<T>[]である間にColMetaData[]オブジェクトを返すことができます。

+0

"List のクラスはありません":あなたが言っていることは分かっていますが、技術的にList のクラスがあります。リスト .class == List.class。 – scottb

+0

ありません 'List .class' :) – ZhongYu

+0

私は同じことを違う方法で言っていると思います。 – scottb

1

ColMetaData<T>[]のことを考えてください。 Javaでは、ジェネリックは厳密にはコンパイル時の問題です。実行時には、それらは存在しなくなります。したがって、実際にランタイムに伝えていることは、ColMetaDataインスタンスの配列を持っているということです。具体的な型です。ただし、配列に任意の型を使用する場合とは異なります。配列型はまだColMetaDataであり、Javaはコンパイル時にこれを判別できます。次に、コンパイラーは、格納するインスタンスが正しいジェネリック型を使用していることを追跡する必要があります。

+0

引数はありません。ただし、これは、ColMetaData インスタンスを宣言し、ColMetaData インスタンスとは別個のものになるという暗黙の保証とは大きく異なります。その区別は、あなたが指摘しているように、パラメータ化された配列型に存在しなくなり、型安全性の保証がすべて消滅します。 – scottb

+0

あなたは正しいかもしれません。私はそれをテストしなければならないだろう。 「型の安全性」はすべてコンパイル時です。コンパイラの処理方法によって異なります。このような状況でコンパイラが失敗した場合、私はそれをバグとみなします。真実は、すべてのタイプの安全性がバイトコードレベルでバイパスできると思われます。モックはおそらくすでにこの点で何かをしています。 – jpmc26

+1

テストする必要はありません。 Angelika LangerはジェネリックFAQでいくつかのテストを行っています:http://www.angelikalanger.com/GenericsFAQ/FAQSections/ParameterizedTypes.html#FAQ104 – scottb

関連する問題