Java Forum / General / April 2007
forEach and Casting
Jason Cavett - 22 Apr 2007 18:32 GMT I have a question about the use of the foreach statement in Java 1.5.
Currently, the collection I'm using an Iterator over contains objects of a Generic type (an abstract class). When I get the object from the collection, I must cast it to the more specific type so I can use the various methods. There is no way to change this.
Is there any way, using the foreach statement in place of using an Iterator, to cast to the right type? I'm thinking something like this...
Collection<Generic> genericCollection = new ArrayList<Generic>(); genericColelction = doSomeStuffToGetGenericCollection();
// this is the part I'm not sure about - can I even do something like this? for(Specific o : (Specific) genericCollection) { // do stuff }
Thanks
Tim Hemig - 22 Apr 2007 18:46 GMT > I have a question about the use of the foreach statement in Java 1.5. > [quoted text clipped - 15 lines] > // do stuff > } Seems, that you have only instances of the Specific class in your Collection, if you know, that every one can be cast to it. therfore I would use a Collection of your Specific type. As lang as you do not cast (after test with instanceof) you cannot use the specific /new/ methods.
Another thing: Everything, that gets overloaded is useable, because the abstract class provides the need to implement it. Because you cannot make instances of an akstract class, in your collection are only non abstract classes with the abstract as superclass. So you have valid objects, with an implementation of your method. so there should be no need to cast - but I did not test that case.
Greetings, Tim
Jason Cavett - 22 Apr 2007 19:02 GMT > > I have a question about the use of the foreach statement in Java 1.5. > [quoted text clipped - 33 lines] > > - Show quoted text - I will only have A specific class in the Collection. The problem is, the method that returns the specific class decides which specific class to return depending on the setup of certain components of the system (so it can decide at runtime).
The method "doSomeStuffToGetGenericCollection();" is actually something like this...
public ArrayList<Generic> getDirectDescendentsOfType(Class classType)
I use it with a tree structure so I can get specific children of type classType. So, unfortunately, I'm always going to get back the superclass Generic. Each version of the Specific classes implements Generic, but they also have additional methods depending on the Specific class, so I need the cast to the specific class.
Anyway, I hope that all made sense. Any additional suggestions? Is it possible to cast the entire Collection to a type all in one shot? Should I just cast each individual item as it's used in the foreach loop?
Piotr Kobzda - 22 Apr 2007 20:02 GMT > The method "doSomeStuffToGetGenericCollection();" is actually > something like this... > > public ArrayList<Generic> getDirectDescendentsOfType(Class classType) What about declaring it as:
public <E extends Generic> List<E> getDirectDescendentsOfType(Class<? extends E> classType)
?
> Is > it possible to cast the entire Collection to a type all in one shot? Yes. But you shouldn't do that, it violates a type safety:
for(Specific o : (List<Specific>)(List<?>)genericCollection) { ...
> Should I just cast each individual item as it's used in the foreach > loop? Using as above declared generic method, you won't need to do that. The following should work:
for(Specific o : getDirectDescendentsOfType(Specific.class)) { ...
piotr
Jason Cavett - 22 Apr 2007 21:04 GMT > > The method "doSomeStuffToGetGenericCollection();" is actually > > something like this... [quoted text clipped - 24 lines] > > piotr Wow...excellent. That works.
Now, unfortunately, despite some of the reading I've done, I don't fully understand the notation. Would you mind explaining it as I don't like to use a tool I don't understand for fear of misuse.
Thanks a lot, though. It's appreciated.
Piotr Kobzda - 22 Apr 2007 21:36 GMT > Now, unfortunately, despite some of the reading I've done, I don't > fully understand the notation. Would you mind explaining it as I > don't like to use a tool I don't understand for fear of misuse. Well, that's not very hard to understand. There is a single type parameter (declared with type variable E) which serves two roles, 1) constraints returned list elements type to any valid subclass of your base class, and 2) declares a type (using wildcard to allow subclasses) of Class objects being accepted by the method.
Whatever the actual type parameters are, they must match must that declaration, that's all.
HTH, piotr
Patricia Shanahan - 22 Apr 2007 19:23 GMT > I have a question about the use of the foreach statement in Java 1.5. > [quoted text clipped - 15 lines] > // do stuff > } How about this?
for(Generic oGeneric : genericCollection) { Specific o = (Specific)oGeneric; // do stuff using o }
Patricia
Jason Cavett - 22 Apr 2007 19:45 GMT > > I have a question about the use of the foreach statement in Java 1.5. > [quoted text clipped - 27 lines] > > - Show quoted text - Yeah, I thought about that, but it (somewhat) defeated the purpose for me to move to the new foreach loops, anyway.
I decided to go with something like this:
ArrayList<Specific> var = (ArrayList<Specific>) getDirectDescendentsOfType(Class classType)
And my getDirectDescendentsOfType is defined as...
public ArrayList<? extends Generic> getDirectDescendentsOfType(Class classType) { // stuff }
It works well. The only downside is I get a warning every time I perform the cast above. So, I have to add @SuppressWarnings statement to methods that have this within them. Not a major thing, just somewhat of a pain.
(I'm going to stick with this method unless anybody has any other suggestions.)
Thanks again.
Piotr Kobzda - 22 Apr 2007 20:16 GMT > I decided to go with something like this: > [quoted text clipped - 15 lines] > (I'm going to stick with this method unless anybody has any other > suggestions.) See my previous post in this thread. Generic method declared as there will prevent you from suppressing this warning.
It also allows for a type-safe implementation of that method itself:
List<E> list = new ArrayList<E>(); // traverse tree descendants, and for each do that... if (type.isInstance(element)) { list.add(type.cast(entry)); } ... return list;
piotr
Tom Hawtin - 22 Apr 2007 20:54 GMT > Currently, the collection I'm using an Iterator over contains objects > of a Generic type (an abstract class). When I get the object from the > collection, I must cast it to the more specific type so I can use the > various methods. There is no way to change this. I suggest you really make sure whether you can change it or not. If you are using generics, casts often mean design issues.
> // this is the part I'm not sure about - can I even do something like > this? > for(Specific o : (Specific) genericCollection) { You can quite easily make a "safe" casting iterator.
/** * <strong>{see Iterator#next} * will throw ClassCastException...</strong> */ public static <T> Iterable<T> castIterable( final Class<T> clazz, final Iterable<? super T> iterable ) { return new Iterable<T>() { public java.util.Iterator<T> iterator() { return new java.util.Iterator<T>() { private final java.util.Iterator<? super T> target = iterable.iterator(); public boolean hasNext() { return target.hasNext(); } public T next() { return clazz.cast(target.next()); } public void remove() { target.remove(); } }; } }; }
... for (Specific thing : castIterable(Specific.class, generals)) {
(Disclaimer: Not tested.)
Tom Hawtin
Jason Cavett - 22 Apr 2007 21:20 GMT > > Currently, the collection I'm using an Iterator over contains objects > > of a Generic type (an abstract class). When I get the object from the [quoted text clipped - 42 lines] > > Tom Hawtin Well, the reason it can't easily be changed is because I don't know what class I'm going to want until runtime. It depends on where the user is at in the tree structure since each component in the tree is different (even though they all have the same superclass).
As such, I need a class that can return the class type I want.
Lew - 22 Apr 2007 23:38 GMT > Well, the reason it can't easily be changed is because I don't know > what class I'm going to want until runtime. It depends on where the > user is at in the tree structure since each component in the tree is > different (even though they all have the same superclass). > > As such, I need a class that can return the class type I want. If you define the type polymorphically you do away with casting and complicated generics both.
For example, suppose you had an interface Collectible representing the supertype for the objects you want to store in a Collection.
public interface Collectible { public void doSomethingAppropriate(); }
Now if you have a Collection<Collectible> you simply
Collection<Collectible> stuff = buildCollection(); for( Collectible coll : stuff ) { coll.doSomethingAppropriate(); }
Notice that there is /no/ specific run-time type knowledge needed in the client class.
Let the object itself know what to do in doSomethingAppropriate() instead of demanding that the client class have that inner knowledge. It's called "encapsulation" combined with "polymorphism" and it's a core O-O programming trick.
 Signature Lew
Jason Cavett - 23 Apr 2007 14:01 GMT > > Well, the reason it can't easily be changed is because I don't know > > what class I'm going to want until runtime. It depends on where the [quoted text clipped - 33 lines] > -- > Lew I know what encapsulation and polymorphism is. The problem is, I can't use it in this situation. My tree (in this case) is made up of very different types of objects. The only reason they have a similar superclass is because I needed a common class to use with the tree. However, the underlying information in each subclass is very different depending on the subclass. The only similariy between all the subclasses is that they all have a name property and a certain status. Other than that, all other data is different.
Lew - 23 Apr 2007 14:15 GMT > I know what encapsulation and polymorphism is. The problem is, I > can't use it in this situation. My tree (in this case) is made up of [quoted text clipped - 4 lines] > subclasses is that they all have a name property and a certain > status. Other than that, all other data is different. Could you make a wrapper class that has a common method where each subclass knows what to do inside doSomethingAppropriate() with the object it wraps?
 Signature Lew
Jason Cavett - 23 Apr 2007 15:53 GMT > > I know what encapsulation and polymorphism is. The problem is, I > > can't use it in this situation. My tree (in this case) is made up of [quoted text clipped - 10 lines] > -- > Lew Unfortunately, it's not that simple (and I wish it was. For example, each data object has different information that I need access to. So, I'm not just telling the data to do something that I don't need to worry about, I actually have to get information back and that info is different depending on the class in question.
Tom Hawtin - 23 Apr 2007 00:27 GMT > Well, the reason it can't easily be changed is because I don't know > what class I'm going to want until runtime. It depends on where the > user is at in the tree structure since each component in the tree is > different (even though they all have the same superclass). Have you considered a visitor (might be overblown for your situation).
Tom Hawtin
Jason Cavett - 23 Apr 2007 14:12 GMT > > Well, the reason it can't easily be changed is because I don't know > > what class I'm going to want until runtime. It depends on where the [quoted text clipped - 4 lines] > > Tom Hawtin It may be a little overblown for my situation. I'd have to look into it a little more. Unfortunately, my current timeline doesn't give me the luxery of going back and refactoring a large part of code at the moment. But, I'll make sure to go back and look into it later.
Thanks for the suggestion.
Free MagazinesGet these publications absolutely FREE for up to 12 months. There are no hidden fees and no obligation. Simply choose a title, complete the application form and submit it. Read more ...
|
|
|