2011-01-04 12 views
1

EDIT:ここには大きな違いを見逃してしまったもう一つのしわがあります。このインタフェースとメソッドでJavaジェネリックに何が間違っていますか?

<T extends Bar> T doAnotherThing(List<Foo<T>> foo) { 
    return foo.get(0).doSomething(); 
} 

だけListは、ジェネリッククラス/インタフェースであるという事実に注意を払う、それがListであるという事実を無視してください:doAnotherThingのメソッドシグネチャではなく、次のです。私はそうのようなメソッドを呼び出しています:

abstract class Bar { 
    // some neat stuff 
} 

class BarImpl extends Bar { 
    // some cool stuff 
} 

interface Foo<T extends Bar> { 
    T doSomething(); 
} 

class FooImpl implements Foo<BarImpl> { 
    BarImpl doSomething() { 
     // Does something awesome 
    } 
} 

これは、すべての罰金とダンディで、素晴らしい作品:

doAnotherThing(new ArrayList<FooImpl>); 

だから、私はそうのように定義されたクラスやインタフェースを持っています。

は今、私はそうのような方法があります:

<T extends Bar> T doAnotherThing(List<Foo<T>> foo) { 
    return foo.get(0).doSomething(); 
} 

この方法は完全に異なるクラスの一般的な方法で、上記チェーンの一部ではありません。私は次のように、このメソッドを使用しようとすると

はしかし、私は型が一致しないというエラーを取得しています:

doAnotherThing(new FooImpl()); 

FooImplFoo<T>を実装していたので、私はしないでくださいこれがエラーであるかどうかを確認してください。多分私は何かを誤解しているのだろうか?おかげ

+2

この例では、BarImplはBarを拡張しません。 – AniDev

+2

それは私のために働く。 'BarImpl extends Bar'を忘れたという事実を別にすれば、 – Bozho

+0

あなたはコンパイラエラーメッセージを共有できますか? –

答えて

3

回答は、実際には完全に正しい質問

complilationエラー(型の不一致)で明確化を反映するように変更しました。メソッド定義では、パラメータがList<Foo<T>>であることに注意してください。つまり、リストにはのいずれかが含まれ、Foo<T>であり、メソッドはFoo<T>を実装する任意のオブジェクトを追加する必要があります。List<FooImpl>には、FooImplのインスタンスのみを含めることが許可されているため、その場合はそうではありません。これは動作します:

doAnotherThing(new ArrayList<Foo<BarImpl>>()); 

ミキシングジェネリック医薬品および多型をすぐに非常に複雑なシナリオにつながるので、慎重に行われるべきです。

+0

Michael、これは修正する必要があります。質問をもう一度ご覧ください。ありがとう。 – Polaris878

+0

@ Polaris878:変更された回答、私は今それを持っていると思います。 –

1

BarImpl extends Barとしましょう。私はあなたが最初から意味していたと信じています。

拡張されたFooインターフェイスの外観はどのようになりますか?

interface Foo<T extends Bar> { 
    T doSomething(); 
    T doAnotherThing(Foo<T> foo); 
} 

はそれですか?

すべてが次のimplで動作しますこのような場合は:あなたがそうでなければ、それを定義した場合今

class FooImpl implements Foo<BarImpl> { 

public BarImpl doSomething() { 
    return null; 
} 

public BarImpl doAnotherThing(Foo<BarImpl> foo) { 
    return null; 
} 

} 

、問題がある可能性がありますが:

interface Foo<T extends Bar> { 
    T doSomething(); 
    <T extends Bar> T doAnotherThing(Foo<T> foo); 
} 

のようので、 doAnotherThingには別のジェネリックスパラメータが導入されています。インターフェースのパラメータとメソッドからの1つのパラメータを混同すると、その名前を共有します(例:T)。 public BarImpl doAnotherThing(Foo<BarImpl> foo)はのオーバーライドの適切な方法ではありません、なぜそれがより明確になります

interface Foo<T extends Bar> { 
    T doSomething(); 
    <Y extends Bar> Y doAnotherThing(Foo<Y> foo); 
} 

: は

最後の定義を置き換えることができる(ちなみに、私はJavaは、このような紛らわしい名前の衝突を可能に学ぶために驚きました)この方法。

+0

'doAnotherThing'は' Foo 'の一部ではありません。別のクラスの一部です – Polaris878

+0

です。私の答えは盲目的だった。 –

2

私のために働きます。私は何が原因でエラーが発生しているのか疑問に思っています。以下のコード(すべて1つのファイル、FooBarBaz.java)がコンパイルされますか?私がコードに加えた唯一の変更は、FooImpl.doSomething()を公開させることでした。 (ああ、それは何かを返すように。:)

public class FooBarBaz { 

    <T extends Bar> T doAnotherThing(Foo<T> foo) { 
     return foo.doSomething(); 
    } 

    public static void main(String[] args) { 
     new FooBarBaz().doAnotherThing(new FooImpl()); 
    } 
} 

abstract class Bar { 
    // some neat stuff 
} 

class BarImpl extends Bar { 
    // some cool stuff 
} 

interface Foo<T extends Bar> { 
    T doSomething(); 
} 

class FooImpl implements Foo<BarImpl> { 
    public BarImpl doSomething() { 
     return null; 
    } 
} 
のMac OS 10.6.5でJDK 1.6、IDEA 9で私のために罰金作品

+0

あなたは正しい、これは実際に動作します。しかし、私は上記で強調した(主要な)詳細を逃した。 – Polaris878

1

元の回答が間違っていると思います。次はうまくいくようです。 doSomethingメソッドをpublicにして、Java6の下でうまくコンパイルします。

abstract class Bar { 
    // some neat stuff 
} 

class BarImpl extends Bar { 
    // some cool stuff 
} 

interface Foo<T extends Bar> { 
    public T doSomething(); 
} 

class FooImpl implements Foo<BarImpl> { 
    public BarImpl doSomething() { 
     return null; 
    } 
} 


public class Test { 
<T extends Bar> T doAnotherThing(Foo<T> foo) { 
    return foo.doSomething(); 
} 

} 
関連する問題