The source is from K&B Master Exam and some modification of mine.
The first code is work. But why the next one is failed to compile??
Based on my experiment i think that the return value decide what the type of T. In this case it must be Object.
So i draw the conclusion that the parameter accept List<? extends Object>. But the compiler said that the List<Object> is required.
Could somebody please help me?
How the return value and the parameter is related ?
Steven Landers
Ranch Hand
Joined: Nov 02, 2008
Posts: 30
posted
0
This is sometimes rather tricky. Keep in mind if you have a <? extends T> in your argument, then T will actually be set to whatever the element type of input is - throughout the entire method signature. On the other hand, if you use <? extends Object> your second example will work.
The compiler error is caused because Polymorphism does not apply to elements of collections when assigning a collection object to a collection reference.
i.e. So this is illegal
List<Object> myList = new ArrayList<Integer>();
...and this is legal:
List<Integer> myList = new ArrayList<Integer>();
When we call backwards() and pass 'input' as the parameter, we're setting T to the type 'Integer' throughout the ENTIRE method signature:
This returns a List<Integer> collection, which CANNOT be assigned to a List<Object> collection. If we were to pass a List<Number> object, then T would represent Number...which could not be assigned to either a List<Object> or a List<Integer> collection.
In the argument, if you change T to Object....it works! Why? This is because T is then set to Object, and ? has no effect on it.
Here's how to do precisely what you want:
This forces the arguments element type to extend T - via the generic type declaration K. This returns a type of List<Number> because the user's declared variable is of type List<Number>. If T existed in the argument, then the passed element type would override the T.
Hopefully that didn't confuse anyone further. Eclipse allows one to hover over a given method call like backwards(input) and see how the method signature is interpreted with generics. I'd recommend using Eclipse to help with various 'what if' scenarios.
Good luck!
Ruben Soto
Ranch Hand
Joined: Dec 16, 2008
Posts: 1032
posted
0
You can also explicitly require the generic method to use a specific type:
All code in my posts, unless a source is explicitly mentioned, is my own.
Welly Tambunan
Ranch Hand
Joined: Aug 18, 2008
Posts: 40
posted
0
Thank you Steven and Ruben,
So the parameter decide the T. How about this one. Is that the same thing happen when i use the super keyword?
The code above is successfully compiled. And i can change the String to whatever type and that still succesfully compile.
Could you help me again please?
Ryan Beckett
Ranch Hand
Joined: Feb 22, 2009
Posts: 192
posted
0
That code didn't compile for me. I didn't know you can bound types to methods. Your the man Ruben!
Steven Landers
Ranch Hand
Joined: Nov 02, 2008
Posts: 30
posted
0
For me, that code didn't seem to complile. It's the same issue as before, as we can't set a List<Integer> to a List<Object>. The return value of backwards is Integer due to the argument's setting of the T type.
Ruben Soto
Ranch Hand
Joined: Dec 16, 2008
Posts: 1032
posted
0
Ryan Beckett wrote:That code didn't compile for me. I didn't know you can bound types to methods. Your the man Ruben!
Clint Eastwood is the man. I'm just a man. Jokes aside, I didn't know that either until I read it somewhere. The idea is that most often the compiler can figure out the type based on the argument type at the type of the invocation. But sometimes several types could fit, like in this case, so you can provide the compiler some extra information to make it work the way you want it to.
Ruben Soto
Ranch Hand
Joined: Dec 16, 2008
Posts: 1032
posted
0
The code is compiling for me. I don't understand very well how it's working though, because the return type must be List<String>, which means that T must be resolved to String, but then List<Integer> can't be assigned to List<? super String>. This is an interesting question, and I'd also like to know what's going on.
Steven Landers
Ranch Hand
Joined: Nov 02, 2008
Posts: 30
posted
0
I'd be interested to know how it would compile elsewhere. Of course, one could change this code to make it compile - or perhaps import some non-standard Integer and String classes to let them share a hierarchy ;)
Ruben Soto
Ranch Hand
Joined: Dec 16, 2008
Posts: 1032
posted
0
Steven, can you try compiling from the command line using javac?
Welly Tambunan
Ranch Hand
Joined: Aug 18, 2008
Posts: 40
posted
0
Ruben Soto wrote:Steven, can you try compiling from the command line using javac?
Yes, that's working in my machine with javac command. But i try to use eclipse and that's give me an error.
Is eclipse using the different javac compiler?
Steven Landers
Ranch Hand
Joined: Nov 02, 2008
Posts: 30
posted
0
I'm stumped. It works fine from javac - how the heck? Eclipse is pointing to a 1.6.0_03 and my javac is pointing to a 1.6.0_05 installation. I would like to think they would be similar The classes are all the java.util classes - nothing crazy there.
Ruben Soto
Ranch Hand
Joined: Dec 16, 2008
Posts: 1032
posted
0
Yes, Eclipse uses a proprietary compiler which does not always behave like javac. Someone recently claimed that you can specify a given compiler in Eclipse per project though. I recommend to not use Eclipse at all if you are preparing for the SCJP though.
I agree. Here's the link: http://ej-technologies/jprofiler - if it wasn't for jprofiler, we would need to
run our stuff on 16 servers instead of 3.