Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Method type-parameterized doesn't work in for loop

Tags:

java

I have this types:

abstract class ControlGraphic { 
  //... 
}

class PrecisionControlGraphic extends ControlGraphic {
  //...
}

class AccuracyControlGraphic extends ControlGraphic {
  //...
}

I have a method that returns a List<T> where T is PrecisionControlGraphic or AccuracyControlGraphic depending on type parameter:

 private <T extends ControlGraphic> List<T> getGraphics() {
   List<T> graphics = new LinkedList<T>();
   for (ControlGraphic graphic : getGraphicsFromDB())
     graphics.add( (T) graphic);
  return graphics;
 }

The code below works properly:

List<PrecisionControlGraphic> precisionGraphics = getGraphics();
for (PrecisionControlGraphic graph : precisionGraphics) { ... }

I'd like to know why this other one doesn't:

for (PrecisionControlGraphic graph : getGraphics()) { ... }

Thanks.

like image 842
Héctor Avatar asked Apr 02 '15 07:04

Héctor


1 Answers

The method signature is saying "you can set T to any subclass of ControlGraphic", and that is why the assignment typechecks (because the compiler finds a type T that works, in fact the type is taken from the assigned-to variable).

The "other one" (direct loop) doesn't work because the type T could be any subclass of ControlGraphic, not necessarily PrecisionControlGraphic. The direct loop doesn't work because the type checker in Java does not do full inference like in functional programming languages. The type of the "graph" variable would have to literally be "any subclass of ControlGraphic" for it to be accepted (and this could actually be arranged by making the type a type parameter of the enclosing method).

Another possibility, as pointed out by @Adrian Leonhard is to annotate the call to getGraphics with the desired type:

for (PCG graph : this.<PCG>getGraphics())

But, basically, with any of these solutions, you are misusing generics. All you know in getGraphics is that you are dealing with ControlGraphic objects, and so that method should return List<ControlGraphic>, and your code should perform explicit casting at the places in the code at which the derived type is known.

like image 115
Atsby Avatar answered Sep 30 '22 17:09

Atsby