2

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

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;
}

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

4

4 回答 4

11

Java 已经支持这个特性,你只需要使用它。如需入门,请阅读Sun的通配符教程。

你想要的是以下内容:

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:“<code>ConcreteObject cannot be cast to OtherConcreteObject”——这很糟糕,因为上面的代码应该会成功。

因此,您应该尽量避免使用这种方法。

于 2009-11-17T19:47:54.987 回答
5

它是非法的,原因在Java 泛型教程中有最好的描述

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

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
于 2009-11-17T19:49:19.803 回答
3

为了以您期望的方式支持协变,Java 需要“具体化”的泛型。一个具体化的List<ConcreteObject>人会知道它的元素需要是ConcreteObject. 因此,如果调用者引用了声明为 an 的列表,则该操作List<IObject>AnAlternateImplObject在运行时失败并出现异常——就像数组的类似情况在今天抛出 anArrayStoreException一样。

在添加泛型时,没有人能想出一种在不破坏与现有代码兼容性的情况下具体化类型的方法。而是提供了使用通配符的“有界”泛型类型。但是,如果我没记错的话,从那时起就设计了一种兼容的具体化方法,因此这种变化可能会在遥远的将来重新出现(Java 8?)。

同时,您使用的解决方案是处理这种情况的惯用方式。

于 2009-11-17T19:54:45.533 回答
1

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

于 2009-11-17T19:55:56.973 回答