• Post Reply Bookmark Topic Watch Topic
  • New Topic
programming forums Java Mobile Certification Databases Caching Books Engineering Micro Controllers OS Languages Paradigms IDEs Build Tools Frameworks Application Servers Open Source This Site Careers Other Pie Elite all forums
this forum made possible by our volunteer staff, including ...
Marshals:
  • Campbell Ritchie
  • Tim Cooke
  • paul wheaton
  • Jeanne Boyarsky
  • Ron McLeod
Sheriffs:
  • Paul Clapham
  • Liutauras Vilda
  • Devaka Cooray
Saloon Keepers:
  • Tim Holloway
  • Roland Mueller
Bartenders:

Generics: Shape example does not work as SUN says

 
Ranch Hand
Posts: 249
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Hello Friends

http://java.sun.com/docs/books/tutorial/extra/generics/wildcards.html

In the example provided Sun says:


Now, the type rules say that drawAll() can only be called on lists of exactly Shape: it cannot, for instance, be called on a List<Circle>. That is unfortunate, since all the method does is read shapes from the list, so it could just as well be called on a List<Circle>. What we really want is for the method to accept a list of any kind of shape:



But I tried to see what happens when the method is like this:

public void drawAll(List<Shape> shapes) {
...
}
Actually it compliles and runs fine any idea why?

Please can you check and come back to me which is not right?


See attached file:



Would appreciate if you can post your thaughts on this?
 
Author
Posts: 12617
IntelliJ IDE Ruby
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
It won't compile for me, gives a warning saying it can't be applied.

How are you compiling this?
 
Mohamed Farouk
Ranch Hand
Posts: 249
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Hello

I am using spring source ide and i tried again at home just copy/paste the code and run it again


This is the output.
Not sure why this is problem for you
 
David Newton
Author
Posts: 12617
IntelliJ IDE Ruby
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

You're passing in a list of Shape, of course *that* will run. That's what the tutorial says as well.

The tutorial says that passing a List<Circle> (or any other Shape subclass) *won't* compile, which is correct.

I'm not sure what your question is, I guess; sorry.
 
Rancher
Posts: 600
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
David,

I think he's confusing passing a List<Circle>, with passing a List<Shape> that has some Circle (or other Shape sub-class) members in it.

Mohamed,

A List<Circle> is not a subclass of List<Shape>, even though Circle is a subclass of Shape. Generics don't work that way.

John.
 
Mohamed Farouk
Ranch Hand
Posts: 249
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Thank both for both your quick replies

John

Yes your right I am constructing List<Shape> list = new ArrayList<Shape>(); But if List<Shape> is different from List<Circle> how am i able to add to the ArrayList<Shape> a object of type List<Circle>.


Yes again if I pass List<Circle> = new ArrayList<Circle> the compilation fails on drawAll method. But If I change the drawAll to accept a bounded Shape then works?

Please can you guys shed some light on this behaviour thanks!!!


 
David Newton
Author
Posts: 12617
IntelliJ IDE Ruby
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Mohamed Farouk wrote:Yes your right I am constructing List<Shape> list = new ArrayList<Shape>(); But if List<Shape> is different from List<Circle> how am i able to add to the ArrayList<Shape> a object of type List<Circle>.


Firstly, you're not adding an ArrayList<Shape> to the List<Circle>, you're adding a Circle. And that works because a Circle is-a Shape.

Yes again if I pass List<Circle> = new ArrayList<Circle> the compilation fails on drawAll method. But If I change the drawAll to accept a bounded Shape then works?


What do you mean by a "bounded shape"?

As far as I can tell the tutorial is correct. You can pass a List<Shape> to drawAll(List<Shape>). What's *in* that List<Shape> is anything that extends Shape.

You cannot, however, pass a List<Circle> to drawAll(List<Shape>), just like the tutorial says: a List<Circle> is-NOT-a List<Shape>. But you *can* pass it to drawAll(List<? extends Shape>), also as the tutorial states.
 
John de Michele
Rancher
Posts: 600
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Mohamed:

Have you actually tried adding an ArrayList<Shape> to a List<Circle>? I got an error when I tried. This also fails:

I think you meant adding an object of type Circle to an ArrayList<Shape>? That is possible. Since Circle is a subclass of Shape, Circle is a Shape.

John.
 
Mohamed Farouk
Ranch Hand
Posts: 249
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Guys thanks but
Why is this wrong then
List<Object> ls = new ArrayList<Object>(); // 1
List<String> lo = ls; // 2


An String is a subtype of Object so why cant the assignment work when Like you said List<Circle> can be added to List<Shape> as circle is a shape?

I get compilation error on both assigments
List<Object> ls = new ArrayList<Object>(); // 1
List<String> lo = ls; // 2

and
List<String> ls = new ArrayList<String>(); // 1
List<Object> lo = ls; // 2

Basically it would be better to have clear clarity on the following circumstances.
1. A <T> can be added to another Generic of type List<X> (like if T is a subtype of X)
2. List<T> can be assigned to another Generic of type List <X>
3. <T> can be retrieved from another type <X> (in a for loop)


 
David Newton
Author
Posts: 12617
IntelliJ IDE Ruby
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Like you said List<Circle> can be added to List<Shape> as circle is a shape?


Please stop saying "a List<Circle> can be added to a List<Shape>". That is incorrect. A Circle can be added to a List<Shape>, because a Circle is-a Shape.

But that's not what the code above is doing: there you're trying to *assign* a List<Object> to a List<String>, which as the tutorial states, will not work.How about:Now does it make sense?
 
Sheriff
Posts: 22821
132
Eclipse IDE Spring Chrome Java Windows
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Mohamed Farouk wrote:List<Object> ls = new ArrayList<Object>(); // 1
List<String> lo = ls; // 2

and
List<String> ls = new ArrayList<String>(); // 1
List<Object> lo = ls; // 2


It's a good thing both do not compile.

If they would compile, the first would allow this:
The second would allow this:
Using List<? extends Object> solves this issue by simply not allowing adding anything except null.
 
Ranch Hand
Posts: 135
4
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Yes again if I pass List<Circle> = new ArrayList<Circle> the compilation fails on drawAll method. But If I change the drawAll to accept a bounded Shape then works?



If you modify drawAll as:

You're writing that 'drawAll takes as parameter a List object; the List is parameterised with a concrete but unknown subtype of Shape'.
If you invoke this with List<Circle> or List<Rectangle> or List<Shape>, they will all work.
When you retrieve objects from such a List, they'll be of type Shape. You cannot add objects of any type to such a List, to avoid violating the contract that it contains a specific (although unknown) subtype of Shape; say it was a List<Circle>, and you'd be able to add Rectangle objects if add() was allowed on such a List. Note that add(aRectangle) is legal is the List is List<Shape>, as then the guarantee is simply that it holds Shapes.

You can play a trick with such unknown but concrete subtypes. Say you have a generic interface implemented by some classes (I used Foo<S extends Shape>, but this could be List<S extends Shape>), and you want to write a class that can work with any of those implementations.


This way, type safety is guaranteed within doUseFoo.
 
John de Michele
Rancher
Posts: 600
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Mohamed:

The reason it doesn't work is because generics are not transitive. In other words, Circle is a subclass of Shape, but List<Circle> is not a subclass of List<Shape>.

John.
 
What's a year in metric? Do you know this metric stuff tiny ad?
Smokeless wood heat with a rocket mass heater
https://woodheat.net
reply
    Bookmark Topic Watch Topic
  • New Topic