aspose file tools*
The moose likes Beginning Java and the fly likes Why generic wildcard could bypass the type safety? Big Moose Saloon
  Search | Java FAQ | Recent Topics | Flagged Topics | Hot Topics | Zero Replies
Register / Login
JavaRanch » Java Forums » Java » Beginning Java
Bookmark "Why generic wildcard could bypass the type safety?" Watch "Why generic wildcard could bypass the type safety?" New topic
Author

Why generic wildcard could bypass the type safety?

L Yan
Greenhorn

Joined: Apr 25, 2006
Posts: 18
Hello,

I understand why this case doesn't work. And indeed it's a compile error of "Cannot cast from List<Integer> to List<Number>".



However, I don't understand why changing the childList to use wildcard could work. I am more confused by the childList could even add and print a non-integer. Does it violate the type safety?


Thank you.
Campbell Ritchie
Sheriff

Joined: Oct 13, 2005
Posts: 38363
    
  23
Sounds like the thing about Cage<Animal> Cage<Lion> and Cage<Butterfly> in the Java Tutorials: Here: look for "wildcards".
Henry Wong
author
Sheriff

Joined: Sep 28, 2004
Posts: 18717
    
  40

Why generic wildcard could bypass the type safety?


The assigment to a generic wildcard does not bypass the type safety. It is the next line, where you cast the list to something else, that broke the type check.

Henry


Books: Java Threads, 3rd Edition, Jini in a Nutshell, and Java Gems (contributor)
L Yan
Greenhorn

Joined: Apr 25, 2006
Posts: 18
I understand why we could not add an element to List<? extends Number>. It is illegal to do:



That's why I do (List<Number>)childList. What I don't understand why it doesn't throw ClassCastException when parentList.add(3.14). Because the underlying list is a ArrayList<Integer> and 3.14 is not a integer, when Java tries to implicitly convert 3.14 to integer, is it a ClassCastException?



Act
Rob Spoor
Sheriff

Joined: Oct 27, 2005
Posts: 19670
    
  18

Because both references regard the contents as Number, and 3.14 is a Double, and therefore also a Number. It would fail if you would cast the list back to a List<Integer>.


SCJP 1.4 - SCJP 6 - SCWCD 5 - OCEEJBD 6
How To Ask Questions How To Answer Questions
Henry Wong
author
Sheriff

Joined: Sep 28, 2004
Posts: 18717
    
  40

I understand why we could not add an element to List<? extends Number>. It is illegal to do:


So you understand that adding is "illegal"? But why is it "illegal"? Because it can violate the type safety !!


That's why I do (List<Number>)childList. What I don't understand why it doesn't throw ClassCastException when parentList.add(3.14). Because the underlying list is a ArrayList<Integer> and 3.14 is not a integer, when Java tries to implicitly convert 3.14 to integer, is it a ClassCastException?


Generics is only at compile time. ClassCastExceptions happen at runtime, when the generic type has already been erased.


IOWs, if you use generics, try your best to *not* cast anything... you need to let the generic do it's work.

Henry
L Yan
Greenhorn

Joined: Apr 25, 2006
Posts: 18
Henry Wong wrote:
IOWs, if you use generics, try your best to *not* cast anything... you need to let the generic do it's work.
Henry


I definitely agree with you. I don't really want to do cast List<? extends Number> to List<Number>. But it doesn't seem that I have other choice. I have this set of API:



SomeFactory class is responsible to create a instance of BasePOJO's subclass and populate the data using the template. The ABC class is responsible to return an appropriate instance of SomeFactory according to the pojo Class passed in. And XYZ class actually uses the SomeFactory to create an instance of BasePOJO's subclass. For example, BasePOJO could be Animal. Then we could have SomeFactory<Cat> and SomeFactory<Dog>. If we do XYZ.generate(Cat cat), it would retrieve SomeFactory<Cat> and use SomeFactory<Cat>.createByTemplate(Cat catTemplate) to get a Cat instance.

The problem is: this.getABC().getFactory(pojo.getClass()) returns a SomeFactory<? extends BasePOJO> instead of SomeFactory. So I could not call SomeFactory<? extends BasePOJO>.create(pojo). It's compile error.

"The method createByTemplate(capture#2-of ? extends BasePOJO) in the type SomeFactory<capture#2-of ? extends BasePOJO> is not applicable for the arguments (BasePOJO)"

That's why I do:


Please let me know your suggestion how to make this design better and if possible how to avoid casting generic. Thank you very much.

I am not sure whether this question is still falling into the original thread. I could start a new thread if necessary.
Henry Wong
author
Sheriff

Joined: Sep 28, 2004
Posts: 18717
    
  40

But it doesn't seem that I have other choice.


That's fine..... But you are complaining that generics can't detect the type correctly, when you are forcing the type.

And BTW, if you are getting "errors" because the type is wrong -- after you forced the type -- doesn't that tell you that generics was right in not allowing the operation?

Henry
L Yan
Greenhorn

Joined: Apr 25, 2006
Posts: 18
Henry Wong wrote:

And BTW, if you are getting "errors" because the type is wrong -- after you forced the type -- doesn't that tell you that generics was right in not allowing the operation?

Henry


I agree with you that it's not because generic is wrong that I have to cast the a generic type to a non-generic type. I guess the question in my previous thread is how to update the design to use the generic correctly and avoid any manual casting. Thank you very much for your reply.

 
I agree. Here's the link: http://aspose.com/file-tools
 
subject: Why generic wildcard could bypass the type safety?