如果不指定泛型类型,方法不会返回元素列表,而只返回列表

时间:2013-01-29 15:36:19

标签: java generics

在使用Java中的泛型时,我有点不方便。请考虑以下代码:

/**
 * 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!
}

在main方法中,如果我没有为'MyElementList'指定类型参数,'getElements()'方法只返回'List',而不是'List&lt; MyElement&gt;'。这很不方便,因为如果我想迭代每个'MyElement',我需要引入另一个变量作为临时列表,如代码所示。

  • 为什么'getElements()'方法没有返回'List&lt; MyElement&gt;'?
  • 没有对'MyElementList'进行重大更改我有什么办法可以解决这个问题吗?
  • 这是一个糟糕的设计实践吗?

我使用的IDE是Netbeans 7.2

提前致谢!

编辑

谢谢大家的快速回复。我对这里的社区印象非常深刻。我得出以下结论:

  • 如果没有指定通用提示,Java会忽略一个类的所有其他相关通用提示 - 这有点蹩脚,但我可以忍受它。
  • 使用泛型时,最佳做法是在创建类的实例时实际指定泛型类型。这似乎是最面向对象的解决方案。

再次感谢!

4 个答案:

答案 0 :(得分: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);
  }
}

它应该有用。

编辑泛型可以看作是Java中的编译时提示,因为Java擦除会将泛型转换为Object。如上所述更新类将告诉编译器仅扩展MyElement符合列表的元素,for(MyElement e : theList.getElements())将起作用。

编辑2 正如其他人所指出的那样(对不起,我乍看之下并没有看到它)也将原始声明更改为:

MyElementList<MyElement> theList = new MyElementList<MyElement>(theElements);

答案 1 :(得分: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());
}

使您的编译符合规。

但我更愿意在实例化/访问它们时指定类所需的类型(以及您的编译器,我猜;))。

答案 2 :(得分:1)

首先不起作用,因为getElements为原始类型

返回List<?>

第二个有效,因为您将其分配给List<MyElement>,忽略了警告。忽略是可以的,因为你知道它包含什么,但编译器没有。

答案 3 :(得分:0)

  

为什么getElements()方法不返回List<MyElement>

因为输入了MyElement

  

没有对MyElementList进行重大更改   我能做些什么来解决这个问题?

您可以使用通配符:

List<MyElement<?>> someList = getElements();