English 中文(简体)
Are there any plans for Java to add generic collection covariance?
原标题:

I was trying to write some code that looked like this:

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

(Where ConcreteObject implements IObject)

This doesn t work at all. It gives a compiler error. Does Java have plans to support this in the future? What is the best workaround until then? What I ended up doing was:

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

This works and maybe there aren t really any bad side effects of doing it this way. Is this the generally accepted best approach?

最佳回答

Java already supports this feature, you just need to use it. For a primer, read the Wildcards tutorial from Sun.

What you want is the following:

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

Alternatively, may use an unsafe cast:

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

… but this method is rather brittle and will throw a runtime exception (except of signalling a compile error) when you try to access its elements with an invalid type:

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

This will result in the followin ClassCastException at runtime: “ConcreteObject cannot be cast to OtherConcreteObject” – which is rather bad because as the code stands above, it should succeed.

For that reason you should try to avoid this method.

问题回答

It s illegal for reasons best described in Java Generics Tutorial

Taking an example from there and applying it to your case:

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

In order to support covariance in the way you expected, Java needs "reified" generics. A reified List<ConcreteObject> would know that its elements need to be instances of ConcreteObject. So if a caller with a reference to that list declared as an List<IObject> tried to add AnAlternateImplObject, the operation would fail at runtime with an exception—just as the analogous case with arrays throws an ArrayStoreException today.

At the time generics were added, no one could figure out a way to reify types without breaking compatibility with existing code. "Bounded" generic types, using wildcards, were provided instead. However, if I recall correctly, a compatible method for reification has been devised since then, so this change may be back on the table for the distant future (Java 8?).

In the meantime, the solution you ve used is a customary way to handle this case.

Just for interest, if you want really pedantic and rigorous type handling in a language somewhat similar to Java, you can hardly do better than Scala. Baroquely intricate type definitions are what Scala is all about. Prof. Odersky, the author of Scala, is the same guy who originally built generics (more timidly) into Java.





相关问题
Spring Properties File

Hi have this j2ee web application developed using spring framework. I have a problem with rendering mnessages in nihongo characters from the properties file. I tried converting the file to ascii using ...

Logging a global ID in multiple components

I have a system which contains multiple applications connected together using JMS and Spring Integration. Messages get sent along a chain of applications. [App A] -> [App B] -> [App C] We set a ...

Java Library Size

If I m given two Java Libraries in Jar format, 1 having no bells and whistles, and the other having lots of them that will mostly go unused.... my question is: How will the larger, mostly unused ...

How to get the Array Class for a given Class in Java?

I have a Class variable that holds a certain type and I need to get a variable that holds the corresponding array class. The best I could come up with is this: Class arrayOfFooClass = java.lang....

SQLite , Derby vs file system

I m working on a Java desktop application that reads and writes from/to different files. I think a better solution would be to replace the file system by a SQLite database. How hard is it to migrate ...

热门标签