4

I am having a slight inconvenience when working with generics in Java. Please consider the following code:

/**
 * MyElement class is simply a wrapper for a generic object.
 */

public static class MyElement<T> {
    public final T OBJ;

    public MyElement(T obj) {
        this.OBJ = obj;
    }
}

/**
 * MyElementList contains an array list of MyElements of the given type, T.
 * This represents a class that uses a list of MyElements of a certain type,
 * and this list can be accessed in an unmodifiable format.
 */

public static class MyElementList<T> {

    //Properties
    private List<MyElement<T>> elementList = new ArrayList();

    //CTOR
    public MyElementList(List<MyElement<T>> initElements) {
        elementList.addAll(initElements);
    }

    //Getter
    public List<MyElement<T>> getElements() {
        return Collections.unmodifiableList(elementList);
    }

}

public static void main(String[] args) {
    //New list of elements
    //Notice that I did not explicitly specify the type for 'MyElement'
    List<MyElement> theElements = new ArrayList(Arrays.asList(
                new MyElement[] {
                    new MyElement("E 1"),
                    new MyElement("E 2"),
                    new MyElement("E 3")
                }
            ));

    //Also notice I did not explicitly specify the type for 'MyElementList'
    MyElementList theList = new MyElementList(theElements);

    //The following does not work.
    //It seems to not work because theList.getElements() returns a 'List'
    //not necessarily a 'List<MyElement>' which is what I would expect it to
    //return...
    //Why???

    for(MyElement e : theList.getElements()) {
        System.out.println(e.OBJ.toString());
    }

    //Currently my work around is to do the following, but I do not like 
    //having to introduce another variable, and I would rather just do the 
    //one above

    List<MyElement> listOfElements = theList.getElements();
    for(MyElement e : listOfElements) {
        System.out.println(e.OBJ.toString());
    }

    //How come the first 'for-each' loop method does not work?
    //Is there anyway I could get it to work?
    //THANK YOU!
}

In the main method, if I don't specify the type parameter for 'MyElementList' the 'getElements()' method only returns a 'List', not a 'List<MyElement>'. This is inconvenient because if I want to iterate through each 'MyElement' I need to introduce another variable as a temporary list, shown in the code.

  • Why doesn't the 'getElements()' method return a 'List<MyElement>'?
  • Without making significant changes to 'MyElementList' Is there anything I can do to fix this?
  • Is this a bad design practice?

The IDE I am using is Netbeans 7.2

Thanks in advance!

EDIT

Thank you all for your quick responses. I am very impressed with the community here. I have concluded the following:

  • If a generic hint is not specified, Java ignores ALL other associated generic hints for a class - which is kind of lame, but I can live with it.
  • When using generics, it is a best practice to actually specify the generic type when creating an instance of the class. This seems to be the most object oriented solution.

Thanks again!

4

4 に答える 4

2

MyElementList見た目が変わると

public static class MyElementList<T extends MyElement> {

  //Properties
  private List<T> elementList = new ArrayList<T>();

  //CTOR
  public MyElementList(List<T> initElements) {
      elementList.addAll(initElements);
  }

  //Getter
  public List<T> getElements() {
      return Collections.unmodifiableList(elementList);
  }
}

それはうまくいくはずです。

EDITジェネリックは、Java の消去によってジェネリックがオブジェクトに変換されるため、Java ではコンパイル時のヒントと見なすことができます。MyElement上記のようにクラスを更新すると、拡張がリストに適合し、機能する要素のみがコンパイラに通知されますfor(MyElement e : theList.getElements())

EDIT 2他の人が指摘したように(申し訳ありませんが、一見しただけではわかりませんでした)、生の宣言を次のように変更します。

MyElementList<MyElement> theList = new MyElementList<MyElement>(theElements);
于 2013-01-29T15:47:13.433 に答える
1

使用する代わりに

for(MyElement e : theList.getElements()) {
    System.out.println(e.OBJ.toString());
}

あなたが使うことができます

for (Iterator<MyElement> it = theList.getElements().iterator(); it.hasNext();) {
    MyElement e = it.next();
    System.out.println(e.next().OBJ.toString());
}

これにより、コンパイラが準拠します。

しかし、クラスをインスタンス化/アクセスするときに必要なタイプを指定したいと思います(そしてコンパイラーもそうだと思います;))。

于 2013-01-29T15:52:08.313 に答える
1

生のタイプのgetElementsaを返すため、最初は機能しませんList<?>

List<MyElement>2つ目は、警告を無視して、に割り当てたために機能します。何が含まれているのかはわかっているので無視しても問題ありませんでしたが、コンパイラはそうではありません。

于 2013-01-29T15:53:25.017 に答える
0

getElements()メソッドがList<MyElement>

MyElementタイプされているので!

これを修正するためにできることはありますMyElementListか?

おそらくワイルドカードを使用できます:

List<MyElement<?>> someList = getElements();
于 2013-01-29T16:00:37.043 に答える