5

次のコードを想像してみてください。

class A {}
class B extends A {}

interface IA extends Iterable<A> {}
interface IB extends Iterable<B> {}

理想的には、実際にはsを取得できるため、インターフェイスIBも拡張できるようにしたいと思います。IAA

interface IB extends Iterable<B>, IA {}

あるいは

interface IB extends Iterable<B> implements IA {}

ただし、コンパイラはこれらの両方を本当に嫌いであり、概念的にBをどこでもアップキャストせずにAとして使用できるため、これが許可されていれば、コードがはるかに良くなります。

この問題を解決するために利用できる解決策は何ですか?

4

3 に答える 3

9

ジェネリックスの非共分散は、あなたが望むものが実行可能ではないことを意味します(少なくとも一般的な場合では)。

しかし、おそらくワイルドカードはあなたの特定の問題を解決するでしょうか?例えば

void methodThatOperatesOnA(Iterable<? extends A> it) {
    ...
}

itこれにより、要素をsであるかのように抽出できますが、不変条件が維持されることを保証できないためA、コンパイラーはオブジェクトの挿入を禁止します


*その他null のいくつかの奇抜なケース

于 2013-01-18T20:41:50.763 に答える
2

タイプは2つのスーパータイプを持つことはできませんG<X> and G<Y> where X!=Y-おそらく消去のためです。

問題を解決する1つの方法は、反復する型の型パラメーターを使用することです。

interface IA<X extends A> extends Iterable<X>
{
    @Override Iterator<X> iterator();
}
interface IB extends IA<B>
{
    @Override Iterator<B> iterator();
}

私は通常それを避けます、それはただもっと複雑です。


あなたの例では、そもそも拡張するIterable<A>ことはおそらく良い考えではありません。例えば

class Team implements Iterable<Member>
{
    public Iterator<Member> iterator() { ... }
}

for(Member member : team) ...

しかし、チームの概念は、おそらく単なるメンバーの集まりよりも広いものです。それはより明確かもしれません

class Team
{
    Iterable<Member> members() { ... }
}
for(Member member : team.members()) ...

その場合、タイプは次のように設計できます。

interface IA
{
    Iterable<? extends A> members();
}

interface IB extends IA
{
    @Override
    Iterable<? extends B> members();
}

Iterable代わりにもっとリラックスすべきだったかどうかを疑問視することもできます

public interface Iterable<T> 

    Iterator<T> iterator();

する方がいいでしょうか

public interface Iterable<T> 

    Iterator<? extends T> iterator();
于 2013-01-18T21:16:04.443 に答える
1

Javaのジェネリックは共変ではありません。つまり、List<String> instanceof List<Object>falseです。したがって、これはのインスタンスでIBなくIA、したがって、コンパイラの問題の原因であると私は信じています。

新しいクラスを想像してみてくださいclass C extends A {}。C IS-A Aであるため、CはIAに含まれる正当な値になりますが、IBには含まれません。したがって、IBをIAのインスタンスとして使用しようとすると、Cを挿入して、型安全性の保証を破ることができます。

于 2013-01-18T20:36:36.040 に答える