繁体   English   中英

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

[英]Are there any plans for Java to add generic collection covariance?

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

public List<IObject> getObject(){
  ArrayList<ConcreteObject> objects = new ArrayList<ConcreteObject>();
  return objects;
}

(ConcreteObject实现IObject的位置)

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

public List<IObject> getObject(){
  List<IObject> objects = new ArrayList<IObject>();
  return objects;
}

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

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

你想要的是以下内容:

public List<? extends IObject> getObject(){
  ArrayList<ConcreteObject> objects = new ArrayList<ConcreteObject>();
  return objects;
}

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

public <T extends IObject> List<T> getObject(){
  ArrayList<T> objects = (ArrayList<T>) new ArrayList<ConcreteObject>();
  return objects;
}

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

@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.

这将导致在运行时跟随ClassCastException :“ ConcreteObject不能转换为OtherConcreteObject ” - 这是相当糟糕的,因为代码如上所示,它应该成功。

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

由于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

为了以您期望的方式支持协方差,Java需要“具体化”的泛型。 已知的List<ConcreteObject>将知道其元素需要是ConcreteObject实例。 因此,如果具有对该列表的引用的调用者声明为List<IObject>尝试添加AnAlternateImplObject ,则操作将在运行时因异常而失败 - 就像今天阵列的类似情况抛出ArrayStoreException一样。

在添加泛型时,没有人能够找到一种在不破坏与现有代码的兼容性的情况下实现类型的方法。 提供了使用通配符的“有界”泛型类型。 但是,如果我没记错的话,从那时起就已经设计了一种兼容的具体化方法,所以这种变化可能会在不久的将来回到桌面上(Java 8?)。

与此同时,您使用的解决方案是处理此案例的常用方法。

只是为了兴趣,如果你想用一种类似于Java的语言进行真正迂腐和严格的类型处理,你几乎不可能比Scala做得更好。 Scala完全是巴洛克复杂的类型定义。 Scala的作者Odersky教授与最初在Java中构建泛型(更加胆怯)的人是同一个人。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM