forEach and Casting

J

Jason Cavett

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
 
T

Tim Hemig

Jason said:
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
}

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
 
J

Jason Cavett

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- Hide quoted text -

- 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?
 
P

Patricia Shanahan

Jason said:
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
}

How about this?

for(Generic oGeneric : genericCollection) {
Specific o = (Specific)oGeneric;
// do stuff using o
}

Patricia
 
J

Jason Cavett

How about this?

for(Generic oGeneric : genericCollection) {
Specific o = (Specific)oGeneric;
// do stuff using o

}

Patricia- Hide quoted text -

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

Piotr Kobzda

Jason said:
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 said:
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
 
P

Piotr Kobzda

Jason said:
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.)

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
 
T

Tom Hawtin

Jason said:
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
 
J

Jason Cavett

What about declaring it as:

public <E extends Generic> List<E>
getDirectDescendentsOfType(Class<? extends E> classType)

?


Yes. But you shouldn't do that, it violates a type safety:

for(Specific o : (List<Specific>)(List<?>)genericCollection) { ...




Using as above declared generic method, you won't need to do that.
The following should work:

for(Specific o : getDirectDescendentsOfType(Specific.class)) { ...

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

Jason Cavett

I suggest you really make sure whether you can change it or not. If you
are using generics, casts often mean design issues.


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

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

Piotr Kobzda

Jason said:
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
 
L

Lew

Jason said:
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.
 
T

Tom Hawtin

Jason said:
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
 
J

Jason Cavett

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.

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

Jason Cavett

Have you considered a visitor (might be overblown for your situation).

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

Lew

Jason said:
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.

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?
 
J

Jason Cavett

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?

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.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,795
Messages
2,569,644
Members
45,359
Latest member
1854578

Latest Threads

Top