だから、私はこのようなコンストラクタを持つクラスを持っています:
_public FilterList(Set<Integer> labels) {
...
}
_
そして、空のセットで新しいFilterList
オブジェクトを構築したいと思います。彼の著書 『Effective Java』でのJoshua Blochのアドバイスに従って、空のセット用の新しいオブジェクトを作成したくありません。代わりにCollections.emptySet()
を使用します。
_FilterList emptyList = new FilterList(Collections.emptySet());
_
これにより、_Java.util.Set<Java.lang.Object>
_は_Java.util.Set<Java.lang.Integer>
_ではないというエラーが表示されます。 OK、これはどうですか:
_FilterList emptyList = new FilterList((Set<Integer>)Collections.emptySet());
_
これもエラーになります! OK、これはどうですか:
_Set<Integer> empty = Collections.emptySet();
FilterList emptyList = new FilterList(empty);
_
ねえ、うまくいく!しかし、なぜ?結局、Javaは型推論を持たないため、Set<Integer> foo = new TreeSet()
の代わりにSet<Integer> foo = new TreeSet<Integer>()
を行うと、未チェックの変換警告が表示されます。 Set<Integer> empty = Collections.emptySet();
は警告なしでも機能します。
簡単な答えは-Javaの汎用システムでの型推論の制限です。具体的な変数に対してジェネリック型を推論できますが、メソッドパラメーターに対してはできません。
Isuspectこれは、メソッドが所有オブジェクトのランタイムクラスに応じて動的にディスパッチされるため、コンパイル時に(()の場合=汎用情報が解決されます)メソッドパラメーターのクラスが何であるかを確実に知ることはできないため、推測することはできません。変数宣言は素晴らしく、定数なので、できます。
他の誰かが詳細やナイスリンクを提供できるかもしれません。 :-)
いずれの場合でも、次のようなジェネリックコールの型パラメーターを常に明示的に指定できます。
Collections.<Integer>emptySet();
または複数のパラメータを一度に、たとえば.
Collections.<String, Boolean>emptyMap(); // Returns a Map<String, Boolean>
これは、推論が開始されない場合に、キャストするよりも少しきれいに見えることがよくあります。
試してみる
FilterList emptyList = new FilterList(Collections.<Integer>emptySet());
推論が十分でない場合、またはサブタイプを使用できるようにするために、それらを持つメソッドのタイプパラメーターを強制できます。例えば:
// forces use of ArrayList as parameter instead of the infered List
List<String> l = someObject.<ArrayList<String> methodThatTakesTypeParamForReturnType();
これを行いたい:
FilterList emptyList = new FilterList(Java.util.Collections.<Integer>emptySet());
これは、emptySet
メソッドに、そのジェネリックパラメーターがデフォルトのInteger
の代わりにObject
で明示的に指定されることを伝えます。もちろん、この構文は完全にファンキーで直感的ではありません。 :)
Javaには型の推論がありますが、かなり限られています。それがどのように機能し、どのような制限があるのかを正確に知ることに興味があるなら、これは本当に良い読書です:
http://www.angelikalanger.com/GenericsFAQ/JavaGenericsFAQ.html#Type%2BArgument%2BInference