views:

179

answers:

4

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?

+7  A: 

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.

Konrad Rudolph
You sure that'll compile? where's the connection between ConcreteObject and IObject?
Carl Smotricz
Ah, never mind - we're assuming it's in the definition of ConcreteObject.
Carl Smotricz
Thanks, I like this approach.
Ryan Elkins
Note that the reference to the list returned by getObject() cannot be used to add anything to the list, except for null. Since the type of the list is unknown, you can only add null (which is a member of every type) to it.
Ladlestein
-1 This answer is inferior than the way the submitter had already answered his own question! Examine the APIs in java.util -- they *never* use a wildcard in a return type. They also never introduce type parameters where none were really needed. They do these things for good reason -- they would bring no real benefit to users. The submitter totally had the right idea from the start.
Kevin Bourrillion
also, the 'alternative' solution doesn't even behave the way the poster thinks. It won't throw an exception at all. It is, however, a bizarre approach.
Kevin Bourrillion
@Kevin: Take a look at `Object.getClass()` which totally uses wildcards in its return type so your objection is bizarre at best. Granted, it does something different than the OP’s solution but I don’t know his exact use-case and the OP wasn’t satisfied by his solution.As for the alternative version, granted, it throws an exception when *accessing* the objects, not when adding new ones. I’ll correct that. As for being “bizarre” – can you qualify this critique? It’s actually a very common approach, and not at all “bizarre”.
Konrad Rudolph
+4  A: 

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
ChssPly76
Hmm, yeah I can see how that would be a problem.
Ryan Elkins
+2  A: 
erickson
A: 

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.

Carl Smotricz