• 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 all forums
this forum made possible by our volunteer staff, including ...
Marshals:
  • Campbell Ritchie
  • Bear Bibeault
  • Paul Clapham
  • Jeanne Boyarsky
  • Knute Snortum
Sheriffs:
  • Liutauras Vilda
  • Tim Cooke
  • Junilu Lacar
Saloon Keepers:
  • Ron McLeod
  • Stephan van Hulst
  • Tim Moores
  • Tim Holloway
  • Carey Brown
Bartenders:
  • Joe Ess
  • salvin francis
  • fred rosenberger

Generic method fail

 
Ranch Hand
Posts: 175
17
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Why is it that I can call

static <T> void processList2(List<T> l,T t) {}

with

List <Animal> list = new ArrayList<Animal>();

but not

List <? extends Animal> list = new ArrayList<Animal>();

 
Sheriff
Posts: 14758
245
Mac Android IntelliJ IDE Eclipse IDE Spring Debian Java Ubuntu Linux
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
What is the compiler error message?

You have to be careful with declarations like List<? extends Animal>. You might define Cat extends Animal, Dog extends Animal, Cow extends Animal. When you try to put them in a List<? extends Animal>, there's no guarantee whether the things you take out will actually be compatible. That is, you can't assign a Dog instance to a Cat reference variable, even though both of them extend Animal. I think the Java Tutorials on generics and wildcards mention something about this: https://docs.oracle.com/javase/tutorial/extra/generics/wildcards.html
 
Bartender
Posts: 4568
9
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Imagine that what you've got there was valid, and that the second method looks like this:

Now change the earlier line to this:

If the previous version was allowed, this would have to be allowed as well. There's no problem assigning an ArrayList<Dog> to a List<? extends Animal> reference. But now there's a problem. Inside the method we are now adding an Animal object to an ArrayList<Dog>. That shouldn't be possible: it breaks type safety.

So what made it unsafe? Being able to call processList2(List<T> l,T t) with a List <? extends Animal> and an Animal as arguments. So the compiler won't allow that.

Most of the rules related to what you can and can't do with generics are a bit like this - things are disallowed if allowing them would give you a way of breaking type-safety, even if that's not immediately obvious.
 
Joe Bishara
Ranch Hand
Posts: 175
17
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
The compiler error is

The method processList2(List<T>, T) in the type Test is not applicable for the arguments (List<capture#2-of ? extends Animal>, Animal)

It looks like the problem is not the List<? extends Animal> argument but the Animal argument

I find this confusing because I intend to pass an Animal argument but I do not intend to add the Animal to the List since I know that the compiler will not allow this.
 
author
Posts: 23853
141
jQuery Eclipse IDE Firefox Browser VI Editor C++ Chrome Java Linux Windows
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator

Joe Bishara wrote:The method processList2(List<T>, T) in the type Test is not applicable for the arguments (List<capture#2-of ? extends Animal>, Animal)



Basically, the compiler can't find a type for T that fits. Make sense. Obviously, the compiler can't allow a method to be called, when the method arguments can't be matched -- this is no different then any other argument mismatch.

Henry
 
Matthew Brown
Bartender
Posts: 4568
9
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator

Joe Bishara wrote:I find this confusing because I intend to pass an Animal argument but I do not intend to add the Animal to the List since I know that the compiler will not allow this.



But with a method signature of static <T> void processList2(List<T> l,T t) the compiler would allow it. Adding a T to a List<T> is fine, so you can add it in that method with no problem. The compiler has to stop you calling the method with those arguments in the first place.
 
Joe Bishara
Ranch Hand
Posts: 175
17
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Am I correct in assuming that

static <T> void processList2(List<T> l,T t) {}

will accept

1. List <Animal> list = new ArrayList<Animal>();

or

2.List <? super Animal> list = new ArrayList<Animal>();

but not

3.List <? extends Animal> list = new ArrayList<Animal>();

because 1. and 2. have a lower bound (and the compiler can infer the type of T from the lower bound) but 3. does not have a lower bound?
 
Matthew Brown
Bartender
Posts: 4568
9
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
I'm not convinced the second one would be allowed, but I'm not 100% sure - you'd have to ask the compiler . But I can see a similar problem to the one I described occurring when you extract a value:

Now what happens if you initialised the list with List <? super Animal> list = new ArrayList<Object>() ?

So I expect that when the signature specifies a non-bounded type, it needs to be given a non-bounded type.
 
Joe Bishara
Ranch Hand
Posts: 175
17
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator

Now what happens if you initialised the list with List <? super Animal> list = new ArrayList<Object>() ?


static <T> void processList2(List<T> l,T t) {}

will accept this List

List <? super Animal> list = new ArrayList<Object>

 
Junilu Lacar
Sheriff
Posts: 14758
245
Mac Android IntelliJ IDE Eclipse IDE Spring Debian Java Ubuntu Linux
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
I know you're going through this exercise to try understand the mechanics of generics in Java, and that's fine.

But here's some food for thought: I have been programming with Java for a long time and I cannot recall having to deal with this kind of problem at all. I just have never found a need to do this in the real-world projects that I have worked on. Yes, I have, on the rare occasion, written my own generic classes and methods but for the most part, my dealings with generics have been with what the standard API classes provide. So unless you're writing a lot of code for general-use libraries or frameworks, I doubt you'll find yourself in a situation where this stuff you're exploring really matters.

Nonetheless, if I did happen to run across this problem in my work, my approach would be to NOT fight the language and try to bend it to my will. I would ask myself first, "Why is this so difficult? Is my design too complicated? What can I do differently that would make things simpler and easier than this?"

This is why I find example class hierarchies like Animal, Cat, Dog, etc. to be very limited in usefulness when trying to learn practical things about Java. They just don't reflect or translate to real-world designs and problems that well.
 
Please do not shoot the fish in this barrel. But you can shoot at this tiny ad:
Sauce Labs - World's Largest Continuous Testing Cloud for Websites and Mobile Apps
https://coderanch.com/t/722574/Sauce-Labs-World-Largest-Continuous
  • Post Reply Bookmark Topic Watch Topic
  • New Topic
Boost this thread!