Collections.emptyList()はList <Object>を返しますか?


269

ジェネリック型パラメーターを推論するためのJavaのルールをナビゲートするのに問題があります。オプションのリストパラメータがある次のクラスを考えてみます。

import java.util.Collections;
import java.util.List;

public class Person {
  private String name;
  private List<String> nicknames;

  public Person(String name) {
    this(name,Collections.emptyList());
  }

  public Person(String name,List<String> nicknames) {
    this.name = name;
    this.nicknames = nicknames;
  }
}

私のJavaコンパイラーは次のエラーを出します:

Person.java:9: The constructor Person(String, List<Object>) is undefined

しかし、ではなくCollections.emptyList()タイプを返します。キャストを追加しても役に立たない<T> List<T>List<Object>

public Person(String name) {
  this(name,(List<String>)Collections.emptyList());
}

収量

Person.java:9: inconvertible types

EMPTY_LIST代わりに使用emptyList()

public Person(String name) {
  this(name,Collections.EMPTY_LIST);
}

収量

Person.java:9: warning: [unchecked] unchecked conversion

次の変更により、エラーが解消されます。

public Person(String name) {
  this.name = name;
  this.nicknames = Collections.emptyList();
}

私がここで実行しているタイプチェックルールと、それを回避する最善の方法を誰かが説明できますか?この例では、最後のコード例で十分ですが、クラスが大きい場合は、コードを複製せずに、この「オプションのパラメーター」パターンに従ってメソッドを記述できるようにしたいと思います。

追加のクレジットの場合:EMPTY_LISTではなく、emptyList()いつ使用するのが適切ですか?


1
すべてのJava Generics関連の質問については、Philips WadlerのMaurice Naftalinによる「Java Generics and Collections」を強くお勧めします。
Julien Chastang 2008年

回答:


447

発生している問題は、メソッドemptyList()がを返してもList<T>、型が指定されていないため、デフォルトでが返されることList<Object>です。typeパラメータを指定して、コードを次のように期待どおりに動作させることができます。

public Person(String name) {
  this(name,Collections.<String>emptyList());
}

これで、直接代入を行うときに、コンパイラーがジェネリック型パラメーターを把握できます。これは型推論と呼ばれます。たとえば、次のようにした場合:

public Person(String name) {
  List<String> emptyList = Collections.emptyList();
  this(name, emptyList);
}

次に、emptyList()呼び出しは正しくを返しますList<String>


12
とった。MLの世界から来ると、Javaが正しい型を推測できないのは奇妙です。仮パラメーターの型とemptyListの戻り型は明らかに単一化可能です。しかし、型推論者は「ベビーステップ」しか実行できないと思います。
Chris Conway、

5
いくつかの単純なケースでは、この場合、コンパイラーが欠落している型パラメーターを推測することは可能に思えるかもしれませんが、これは危険な場合があります。メソッドの複数のバージョンが異なるパラメーターで存在する場合、誤ったバージョンを呼び出す可能性があります。そして、2番目のものはまだ存在していないかもしれません...
ビルミシェル

13
その "Collections。<String> emptyList()"という表記は本当に奇妙ですが、理にかなっています。Enum <Eよりも簡単Enum <E >>を拡張します。:)
チアゴチャベス

12
Java 8では、型パラメーターを指定する必要はありません(可能なジェネリック型にあいまいさがなければ)。
Vitalii Fedorenko 2014

9
2番目のスニペットは、型推論を適切に示していますが、もちろんコンパイルされません。の呼び出しthisは、コンストラクターの最初のステートメントでなければなりません。
2016

99

あなたが使いたい:

Collections.<String>emptyList();

emptyListが何をしているかのソースを見ると、実際には単に

return (List<T>)EMPTY_LIST;

26

emptyListメソッドには次のシグネチャがあります。

public static final <T> List<T> emptyList()

それ<T>それは結果が割り当てられている変数の型からジェネリックパラメータTの値を推測することを単語リスト手段の前に。したがって、この場合:

List<String> stringList = Collections.emptyList();

その後、戻り値は型の変数によって明示的に参照されるList<String>ため、コンパイラはそれを理解できます。この場合:

setList(Collections.emptyList());

コンパイラがジェネリック型を把握するために使用する明示的な戻り変数はないため、デフォルトでに設定されObjectます。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.