有没有计划让Java添加泛型集合协方差?

Rya*_*ins 2 java collections covariance

我试图编写一些看起来像这样的代码:

public List<IObject> getObject(){
  ArrayList<ConcreteObject> objects = new ArrayList<ConcreteObject>();
  return objects;
}
Run Code Online (Sandbox Code Playgroud)

(ConcreteObject实现IObject的位置)

这根本不起作用.它给出了编译器错误.Java是否有计划在未来支持这一点?到那时为止,最好的解决方法是什么?我最终做的是:

public List<IObject> getObject(){
  List<IObject> objects = new ArrayList<IObject>();
  return objects;
}
Run Code Online (Sandbox Code Playgroud)

这可行,也许这样做没有任何不良副作用.这是普遍接受的最佳方法吗?

Kon*_*lph 11

Java已经支持此功能,您只需要使用它.有关入门知识,请阅读Sun 的Wildcards教程.

你想要的是以下内容:

public List<? extends IObject> getObject(){
  ArrayList<ConcreteObject> objects = new ArrayList<ConcreteObject>();
  return objects;
}
Run Code Online (Sandbox Code Playgroud)

或者,可以使用不安全的演员:

public <T extends IObject> List<T> getObject(){
  ArrayList<T> objects = (ArrayList<T>) new ArrayList<ConcreteObject>();
  return objects;
}
Run Code Online (Sandbox Code Playgroud)

...但是当您尝试使用无效类型访问其元素时,此方法相当脆弱并将抛出运行时异常(发出编译错误信号除外):

@SuppressWarnings("unchecked")
public <T extends IObject> List<T> getObject(){
  ArrayList<T> objects = (ArrayList<T>) new ArrayList<ConcreteObject>();
  objects.add(new ConcreteObject());
  return objects;
}

…
List<OtherConcreteObject> objects = getObject(); // Works.
OtherConcreteObject obj = OtherConcreteObject.get(0); // Throws CCE.
Run Code Online (Sandbox Code Playgroud)

这将导致ClassCastException运行时跟随:" ConcreteObject无法转换为OtherConcreteObject" - 这是相当糟糕的,因为代码站在上面,它应该成功.

因此,您应该尝试避免使用此方法.

  • 啊,没关系 - 我们假设它在ConcreteObject的定义中. (2认同)
  • @Kevin:看一下`Object.getClass()`,它在返回类型中完全使用通配符,所以你的异议最多也是奇怪的.当然,它与OP的解决方案有所不同,但我不知道他的确切用例,OP不满意他的解决方案.对于替代版本,在授予时,它会在*访问*对象时抛出异常,而不是在添加新对象时抛出异常.我会纠正的.至于"离奇" - 你能否批评这个批评?这实际上是一种非常常见的方法,而且根本不是"离奇". (2认同)

Chs*_*y76 5

由于Java Generics Tutorial中最佳描述的原因,这是非法的

从那里做一个例子并将其应用于您的案例:

List<ConcreteObject> concreteObjects = new ArrayList<ConcreteObject>();
List<IObject> objects = concreteObjects; // assume it's legal
objects.add(new IObject() { // anonymous or some other (incompatible with ConcreteObject) implementation
});
ConcreteObject co = concreteObjects.get(0); // Profit! er... I mean error
Run Code Online (Sandbox Code Playgroud)