Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Java: For each loop , Iteration over extended objects

My Question might be very simple,

I have a class Result with some inner fields , setters and getters.

Additionally, i have class Special1Result which extends Result and includes several more fields and Special2Result with some more data.

In different class Dispatcher, i have written the following method:

processResults(List<? extends Result> results), which is only familiar with Result (I need this method to query if there is specific field in the extended Result object - i am using annotations).

So i have decided to use the extended for-each loop: for (Result res : results) {}

So what is my question ? i am trying to find over the web how to write this for loop for extended objects, e.g. something like this for (? extends Results res: results){}

Is it possible? How is the correct way to write it?

like image 981
Michael Avatar asked Sep 27 '12 14:09

Michael


4 Answers

All you know about a List<? extends Result> is that each element will be a Result - so that's all you can put in the enhanced for loop syntax.

If you need members which aren't declared in Result, you'll need to cast inside the loop:

for (Result result : results) {
    if (result instanceof CleverResult) {
        CleverResult clever = (CleverResult) result;
        // Use clever here
    }
}

Think about what you'd write if you weren't using an enhanced for loop - you'd still need to write the cast, wouldn't you?

Of course, if you know that the list should really only contain one specific type, you can always cast unconditionally in the loop.

like image 147
Jon Skeet Avatar answered Oct 16 '22 11:10

Jon Skeet


I am trying to find over the web how to write this for loop for extended objects, e.g. something like this

for (? extends Results res: results){}

No, this is not possible: you cannot statically type items supplied dynamically at run-time.

How is the correct way to write it?

You are already doing it:

for (Results res: results) {
}

If you would like to test for Special2Result inside that loop, you can do it, but usually it tells that your design can be improved. A better alternative is to use a mechanism of double dispatch, such as the Visitor Pattern, to hide the details of special treatment for your subclasses.

like image 43
Sergey Kalinichenko Avatar answered Oct 16 '22 10:10

Sergey Kalinichenko


Java has type erasure - the concrete type parameters of collections are not present at runtime.

So if you have a List, the java compiler will ensure that no code will put anything into the list that isnt a subclass of Result.

Accordingly, at runtime, all your loop can know is that the contents are all subclasses of Result - so the only way to loop over them is as a set of references to Result, with whatever polymorphic behaviour that is present as a result of any subclasses that are in the list.

like image 1
PaulJWilliams Avatar answered Oct 16 '22 11:10

PaulJWilliams


Since your concrete sublasses only differs by nature of fields, I would suggest you to benefit from simple polymorphism.

You would end up with a Result interface/abstract class defining an execute() method class implemented by as many classes or subclasses as you need containing themselves action to do.

Therefore, your client code could merely use:

for (Result res : results){    //results being as a List<Result> type
  res.execute(); 
}
like image 1
Mik378 Avatar answered Oct 16 '22 10:10

Mik378