52

Java ジェネリック型パラメーターを下限にバインドできない (つまり、superキーワードを使用する) ことはできないと思います。私はAngelika Langer Generics FAQ がこの件に関して何を言わなければならなかったかを読んでいました. 彼らは、基本的に下限が役に立たない(「意味がない」)ことに帰着すると言います。

確信が持てません。型付きの結果を生成するライブラリ メソッドの呼び出し元に対して、より柔軟に対応できるようにするために、これらを使用することを想像できます。ユーザー指定のサイズの配列リストを作成し、空の文字列で埋めるメソッドを想像してください。簡単な宣言は次のようになります

public static ArrayList<String> createArrayListFullOfEmptyStrings(int i);

しかし、それはクライアントを不必要に制限しています。なぜ彼らはあなたのメソッドを次のように呼び出せないのですか:

//should compile
List<Object> l1 = createArrayListFullOfEmptyStrings(5); 
List<CharSequence> l2 = createArrayListFullOfEmptyStrings(5);
List<String> l3 = createArrayListFullOfEmptyStrings(5);

//shouldn't compile
List<Integer> l4 = createArrayListFullOfEmptyStrings(5);

この時点で、次の定義を試してみたくなります。

public static <T super String> List<T> createArrayListFullOfEmptyStrings(int size) {
  List<T> list = new ArrayList<T>(size);
  for(int i = 0; i < size; i++) {
     list.add("");
  }
  return list;
}

しかし、それはコンパイルされません。このコンテキストでは、superキーワードは不正です。

上記の例は悪い例ですか (以下で言うことを無視します)? ここで下限が役に立たないのはなぜですか? それが有用であるとすれば、Java で許可されていない本当の理由は何ですか?

PS

私は、より良い組織は次のようなものかもしれないことを知っています:

public static void populateListWithEmptyStrings(List<? super String> list, int size);

List<CharSequence> list = new ArrayList<CharSequence>();
populateListWithEmptyStrings(list, 5);

この質問の目的のために、要件により、1 つのメソッド呼び出しで両方の操作を行う必要があるふりをすることができますか?

編集

@Tom Gは(当然のことながら) a を使用すると a よりもどのような利点があるかを尋ねList<CharSequence>ますList<String>。1 つには、返されるリストが不変であると誰も言っていないので、ここに 1 つの利点があります。

List<CharSequence> l2 = createArrayListFullOfEmptyStrings(5);
l2.add(new StringBuilder("foo").append("bar"));
4

6 に答える 6

15

基本的に、それだけでは十分ではありません。

あなたの例は、FAQが呼び出す機能である下限の唯一の利点を指摘していると思いますRestricted Instantiation

要するに、「スーパー」バウンドによって得られるのは、 Number のスーパータイプのみが型引数として使用できるという制限だけです。....

しかし、他の投稿が指摘しているように、この機能でさえ有用性が制限される可能性があります.

ポリモーフィズムと特殊化の性質上、FAQ (非静的メンバーへのアクセス型消去)で説明されているように、上限は下限よりもはるかに便利です。下限によって導入された複雑さは、その限られた価値に値しないと思います。


OP: 私はあなたがそれが有用であることを示したと思いますが、十分に有用ではないことを追加したいと思います. 反論の余地のないキラーユースケースを思いつき、JSRを支持します。:-)

于 2011-02-04T21:20:37.573 に答える
10

仕様では、型パラメーターの下限について説明しています。たとえば、

4.10.2

型変数は、その下限の直接のスーパータイプです。

5.1.10

新しい型変数 ... その下限

型変数は、ワイルドカード キャプチャの結果として合成されたものである場合、(null 以外の) 下限のみを持つようです。言語がすべての型パラメーターの下限を許可する場合はどうなりますか? おそらく大きな問題は発生せず、ジェネリックスを単純にするためだけに除外されています (まあ...)更新下限の型パラメーターの理論的調査は十分に行われていないと言われています。

更新: 下限は問題ないと主張する論文: "Java Type Infererence Is Broken: Can We Fix It" by Daniel Smith

RETRACT: 次の引数は間違っています。OPの例は正当です。

あなたの特定の例はあまり説得力がありません。まず、タイプセーフではありません。返されるリストは確かにList<String>です。別の型として表示するのは安全ではありません。コードがコンパイルされるとします。

    List<CharSequence> l2 = createArrayListFullOfEmptyStrings(5);

次に、非文字列を追加できますが、これは間違っています

    CharSequence chars = new StringBuilder();
    l2.add(chars); 

ではありませんList<String>が、CharSequence のリストのようなものです。ワイルドカードを使用することで、ニーズを解決できます。

public static  List<String> createArrayListFullOfEmptyStrings(int size)  

// a list of some specific subtype of CharSequence 
List<? extends CharSequence> l2 = createArrayListFullOfEmptyStrings(5);

// legal. can retrieve elements as CharSequence
CharSequence chars = l2.get(0);

// illegal, won't compile. cannot insert elements as CharSequence
l2.add(new StringBuilder());
于 2011-02-04T23:49:09.610 に答える
0

その時点で、リストを入力するとどのような利点が得られますか? 返されたコレクションを反復処理する場合でも、次のことができるはずです。

for(String s : returnedList) {
CharSequence cs = s;
//do something with your CharSequence
}
于 2011-02-04T20:47:16.573 に答える
-2

うーん、わかりました - これで作業しましょう。メソッドを定義します。

public static <T super String> List<T> createArrayListFullOfEmptyStrings(int size) {

どういう意味ですか?これは、あなたのメソッドを呼び出すと、String のスーパークラスのリストが返されることを意味します。おそらく、文字列のリストを返します。おそらく、オブジェクトのリストを返します。知らない。

涼しい。

List<Object> l1 = createArrayListFullOfEmptyStrings(5);

あなたによると、それはコンパイルする必要があります。しかし、そうではありません。Object - のリストに Integer を入れることができl1.add(3)ます。ただし、文字列のリストを返す場合、それは違法です。

List<String> l3 = createArrayListFullOfEmptyStrings(5);

あなたによると、それはコンパイルする必要があります。しかし、そうではありません。l3.get(1)常に文字列を返す必要があります...しかし、そのメソッドはオブジェクトのリストを返した可能性があります。つまり、l3.get(1) はおそらく整数である可能性があります。

機能する唯一のことは

List<? super String> l5 = createArrayListFullOfEmptyStrings(5);

私が知っているのは、安全に を呼び出すことl4.put("foo")ができ、安全に を取得できるということだけですObject o = l4.get(2)

于 2011-02-16T08:00:55.220 に答える