2011-02-10 9 views
7

を実装したときに、私は、脳のけいれんを抱えている:私はpublic interface SomeInterfacestatic private class SomeClassを持っていると私の方法のいずれかからList<SomeInterface>を返すようにしようと、私は取得しています(以下return list;ライン上の)エラー:私は、新しいリストを作成することなく、この問題を解決するにはどうすればよいのjava:<SomeInterface>リストに一覧<SomeClass>から変換工assがSomeInterface

Type mismatch: cannot convert from List<GenericList1.SomeClass> to 
List<GenericList1.SomeInterface> 

明確化:私的に私がパブリックインターフェイスでものを超え工assのメソッドへの将来のアクセスを許可するようにList<SomeClass>を維持したいので、私はリストが(おそらく、明白な解決策)List<SomeInterface>として作成する必要はありません。これは以下の例の場合は表示されませんが、私の実際のプログラムではこれが必要です。

import java.util.ArrayList; 
import java.util.List; 

public class GenericList1 { 

    public interface SomeInterface 
    { 
     public int getX(); 
    } 

    private static class SomeClass implements SomeInterface 
    { 
     final private int x; 
     @Override public int getX() { 
      return this.x; 
     }  
     public SomeClass(int x) { this.x = x; } 
    } 

    public static void main(String[] args) { 
     List<SomeInterface> list = createList(10); 
     printList(list); 
    } 

    private static void printList(List<SomeInterface> list) { 
     for (SomeInterface si : list) 
      System.out.println(si.getX()); 
    } 

    private static List<SomeInterface> createList(int n) { 
     List<SomeClass> list = new ArrayList<SomeClass>(); 
     for (int i = 0; i < n; ++i) 
      list.add(new SomeClass(i)); 
     return list; 
    } 
} 

答えて

23

あなたが

private static List<? extends SomeInterface> createList(int n) { ... 

と同様に、他のリスト宣言として、あなたの方法を再定義する必要があります。これにより、の値だけを読み取る限り、汎用リストをポリモフィックに扱うことができます。

(あなたがリストに新しい要素を追加したいなら、あなたの代わりにList<? super SomeInterface>を使用する必要があります。)

このイディオムは、PECS略語で知られている - プロデューサー:/消費者を拡張:スーパー、によって造語他の人が指摘したようにList<SomeClass>が場合でもSomeClass implements SomeInterfaceList<SomeInterface>ではありませんので、効果的なJavaの第2版ではジョシュ・ブロッホ、項目28

は、このイディオムが必要とされています。この理由は、参考文献で完全に説明されています。

+0

ああ、これは正常です。私の実際のプログラムでは、Collections.unmodifiableList()によってラップされたList <>を返していますので、それらは読み込み専用になります。 –

+0

答えはアイテム28へのリンクを持っていましたが、リンクは現在死んでいます。この本のPDFは以下のサイトから入手できます:https://github.com/ldfaiztt/CSE331/blob/master/Effective.Java.2nd.Edition.May.2008.3000th.Release.pdf – Paul

6

List<Derived>は、Derived extends Baseであっても、List<Base>とは全く関係ありません。

クラスが階層を共有しているという理由だけで、それらのコレクションが行うわけではありません。これは一般的なジェネリックスに当てはまります。

次のようにあなたのコードを変更することができます:

private static List<SomeInterface> createList(int n) { 
     List<SomeInterface> list = new ArrayList<SomeInterface>(); 
     for (int i = 0; i < n; ++i) 
      list.add(new SomeClass(i)); //add a SomeClass object - valid, because it has the interface 
    return list; 
} 
+0

はい、明らかな解決策ですが、私はそれをしたくない。私の編集を参照してください。 –

0
private static List<SomeInterface> createList(int n) { 
    List<SomeInterface> list = new ArrayList<SomeInterface>(); 
    for (int i = 0; i < n; ++i) 
     list.add(new SomeClass(i)); 
    return list; 
} 
+0

それは明らかな解決策ですが、私はそれをしたくありません。私の編集を参照してください。 –

1

を、私はそうのようなメソッドのシグネチャを変更します:戻り値の型でワイルドカードを使用して

private static void printList(List<? extends SomeInterface> list) { 
    for (SomeInterface si : list) 
     System.out.println(si.getX()); 
} 

private static <T super SomeClass> List<T> createList(int n) { 
    List<T> list = new ArrayList<T>(); 
    for (int i = 0; i < n; ++i) 
     list.add(new SomeClass(i)); 
    return list; 
} 

がしばしばありますそれはすべての呼び出しメソッドでワイルドカードを使用する必要があるからです。私はcreateListをジェネリックメソッドにしました。戻り値の型は可能な限り柔軟で、可能な限り具体的なものにすることができます。

関連する問題