7

了解しました。Javaでは次のことは許可されていません。

Foo<?> hello = new Foo<?>();

これは理にかなっています-結局のところ、とにかくすべてをボックス化/ボックス化解除するだけの場合、ジェネリックスのポイントは何ですか?

奇妙なことに、Javaこれを許可します:

Foo<Bar<?>> howdy = new Foo<Bar<?>>();

確かに、これは実際にはより多くのことを達成しますが、ある時点で、Bar動作しているものを取得するためのキャストがあります。しかし、Javaにある程度の特異性があれば、なぜこれが許可されないのでしょうか。

Foo<? extends Mal> bonjour = new Foo<? extends Mal>();

私が尋ねる唯一の理由は、「コンストラクターのクラスパラメーター内のワイルドカード」に依存するように修正していることであり、その背後にある意味/意図を真剣に知りたいと思っています。

編集:私の質問を明確にするために、これらのステートメントはどのような理由で許可/禁止されていますか?「Javaはコンストラクターでワイルドカードを許可しない」ことは知っていますが、問題は、なぜこのような奇妙なことなのかということです。ネストされたワイルドカードで問題がないのに、制限付きワイルドカードが許可されないのはなぜですか?

4

4 に答える 4

5

理論的根拠については、new Foo<?>おそらく次のように記述したほうがよいでしょう。そのためnew Foo<Object>、ここでのコンパイラの制限により、コードをできるだけ読みやすく記述しなければなりません。最後の例も同様になります。これは、で実行できることnew Foo<Mak>()は、Foo<? extends Mal>で実行できないことではないためですFoo<Mal>。逆は真ではないことに注意してください。aは、aFoo<Mal>が受け入れないMal引数を受け入れる可能性Foo<? extends Mal>があります。

一方、あらゆる種類のオブジェクトをFoo処理できるオブジェクトが本当に必要な場合があるので、完全に理にかなっています。これは、type引数に依存しないメソッドにのみアクセスする場合に当てはまります。コンパイラがここで文句を言うことは何もありません。BarFoo<Bar<?>>Bar

于 2012-07-18T22:20:33.903 に答える
3

1番目と3番目の宣言が機能しない理由は、JLS§15.9のためです。

クラスインスタンス作成式で使用される型引数のいずれかがワイルドカード型引数(§4.5.1)である場合、コンパイル時エラーになります。

最初の宣言で?は、はワイルドカードタイプです。3番目の宣言で? extends Malは、はワイルドカードタイプです。

2番目の宣言Bar<?>機能する理由は、がワイルドカードタイプではないためです。Bar<?>のタイプはBarです。

「コンストラクターのクラスパラメーター内のワイルドカード」とはどういう意味ですか?

于 2012-07-18T22:17:13.637 に答える
1

パラメータ化されたタイプのインスタンスをインスタンス化するときは、タイプを指定する必要があります。?? extends Malはタイプではありません。Bar<?>タイプです。詳細については、このページをご覧ください。

2番目のケースの例を次に示します。

Bar<Object> bar1 = ...;
Bar<String> bar2 = ...;
List<Bar<?>> list = new ArrayList<Bar<?>>();
list.add(bar1);
list.add(bar2);

Barインスタンスをリストに格納することを想像できますが、それらのタイプパラメーターを知る必要はありません。

于 2012-07-18T22:16:57.013 に答える
1

new Foo<?>同等に、その型パラメータの範囲を満たす任意の型であるnew Foo<SomeRandomTypeIMadeUp>whereに置き換えることができます。SomeRandomTypeIMadeUp最も簡単な選択は、その型パラメーターの上限を選択することです。たとえば、そうである場合はclass Foo<T extends X>new Foo<X>それで十分です。

プログラムの他の部分とはまったく関係がない場合でも、任意の型のパラメーターを選択できるのはなぜですか?それは危険ではありませんか?答えはノーです。それがまさにそのFoo<?>意味です。typeパラメーターは何でもかまいません。また、それが何であるかに依存することはできません。これは、あなたがやろうとしていることのまったくの不条理を示しています。typeパラメータのタイプに依存するものは何もできないため、で作成されたものnew Foo<?>はほとんど完全に役に立たないでしょう。

ワイルドカードを使用したタイプは一般的に便利です。たとえば、typeの引数を持つことができ、List<?>それに任意のタイプを渡すことができList、それは単にリストからものを取得します。ただし、その場合は、リストを作成していません。リストを作成して渡した関数には、ワイルドカード以外のタイプのパラメーターが含まれている可能性があります。その関数の範囲内で、リストに物事を入れて、それを使って便利なことをすることができます。関数が作成する場合List<?>; これはかなり役に立たないでしょう-あなたはそれに以外の要素を入れることはできませんnull

これがあなたがすることを許されていない理由ですnew Foo<?>:それは全く役に立たないです。ジェネリックを使用したい場合は、おそらくジェネリックを間違って使用しています。そして、あなたが実際にそれを欲している非常にまれなケースでは、すぐに使える代替品がありnew Foo<AnyTypeThatSatisfiesTheBounds>ます。

Foo<Bar<?>>非常に異なります。特定のタイプですBar<?>。あなたがそれに割り当てることができるという意味ではありません。むしろ、それは違法です。のタイプパラメータは、ワイルドカードでない場合は一致する必要があります。また、ワイルドカードとは異なり、を使用すると、オブジェクトをワイルドカードに入れたり、ワイルドカードからオブジェクトを取り出したりできます。Foo<Bar<?>>Foo<Bar<Something>>FooList<Bar<?>>

于 2012-07-18T23:06:12.650 に答える