複数のクラスでのJavaジェネリックワイルドカード


385

Classオブジェクトが必要ですが、それが表すクラスを強制的にクラスAに拡張し、インターフェースBを実装したいと思います。

できます:

Class<? extends ClassA>

または:

Class<? extends InterfaceB>

しかし、私は両方を行うことはできません。これを行う方法はありますか?

回答:


613

実際に、あなたあなたやりたいことをすることができます。複数のインターフェースまたはクラスとインターフェースを提供する場合は、ワイルドカードを次のようにする必要があります。

<T extends ClassA & InterfaceB>

sun.com のGenerics Tutorial、特にページの下部にあるBounded Type Parametersセクションを参照してください。必要に応じて、実際に複数のインターフェースをリストすることができ& InterfaceNameます。

これは任意に複雑になる可能性があります。実例として、のJavaDoc宣言を参照してくださいCollections#max(2行に折り返されています)。

public static <T extends Object & Comparable<? super T>> T
                                           max(Collection<? extends T> coll)

なぜそんなに複雑なのですか?Java Generics FAQで述べたように:バイナリ互換性を維持するため

これは変数宣言では機能しないように見えますが、クラスに一般的な境界を置く場合は機能します。したがって、あなたが望むことをするために、あなたはいくつかのフープを飛び越える必要があるかもしれません。しかし、あなたはそれを行うことができます。あなたはこのようなことをすることができ、あなたのクラスに一般的な境界を置き、それから:

class classB { }
interface interfaceC { }

public class MyClass<T extends classB & interfaceC> {
    Class<T> variable;
}

それを得るvariableにはあなたが望む制限があります。詳細と例については、Generics in Java 5.0の 3ページをご覧ください。<T extends B & C>では、クラス名が最初に来る必要があり、インターフェイスが後に続くことに注意してください。もちろん、リストできるクラスは1つだけです。


94
これは役に立ちます。クラスが最初に来る必要があることは言及する価値があります。「<T extends InterfaceB&ClassA>」とは言えません。
EricS

5
Tに対して同じようにするには、クラスを拡張するか、インターフェイスを実装する必要がありますか?
Ragunath Jawahar 2013

1
@RagunathJawahar:これについては、自由に答えることはできません。いくつかの境界が必要であり、そのうちの1つは、インターフェイスがどこにあり、クラスがどこにあるか、および継承をどのように使用するかを事前に知っています。型パラメーターがクラスまたはインターフェイスになる場合、型パラメーターについて知っておく必要があります。
Eddie

4
回答の最初の行は、「ワイルドカードをこのようなものにする」と言っています。?その表現には何もないので、それは本当に「ワイルドカード」なのでしょうか?型パラメーターが本当にワイルドカードである場合、「一度に2つのものを拡張する」という概念全体を機能させることができないので、質問します。
The111

1
ええ、それは実際にはワイルドカードではなく、OPが要求したものをワイルドカードで実行することはできません。あなたはできるだけではワイルドカードで、効果的に、OPが望んで行います。
エディ

17

「匿名」型パラメーター(つまり、を使用するワイルドカード)を使用?してそれを行うことはできませんが、「名前付き」型パラメーターを使用して行うことはできます。メソッドまたはクラスレベルで型パラメーターを宣言するだけです。

import java.util.List;
interface A{}
interface B{}
public class Test<E extends B & A, T extends List<E>> {
    T t;
}

2
ワイルドカードが許可されないのはなぜですか?つまり、これが有効ではない理由がわかりません:ArrayList <?ClassA&InterfaceB>リストを拡張します。そして、リストから要素を取り出した場合、それをClassA型またはInterfaceB型の変数に割り当てることができます
Mark

ワイルドカードを変数に置き換えるのは素晴らしいテクニックです!ただし、常に機能するとは限りません。たとえば、Javaではワイルドカードを使用できますが、注釈値型では名前型変数を使用できません。
2017
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.