Reputation: 15886
I am doing some Java studying, especially in the area of generics.
I'm fairly familiar with generics in C#, but in Java, it's a whole different story.
I used a few samples that worked just fine for testing, and I am able to replicate most of my C# code in Java just fine.
However, when I try the following example, it doesn't work:
private static <T> void swapKundeData(ArrayList<T> data, int index1, int index2) {
T temporary = (T) data.get(index1);
data.set(index1, data.get(index2)); //Does not compile
data.set(index2, temporary); //Does not compile
}
The error I am receiving is:
The method set(int, capture#5-of ? extends ExtendTest) in the type ArrayList is not applicable for the arguments (int, ExtendTest)
An equivalent of this works just fine in C# - so what's going on?
I've read that Java has received a lot of criticism when it comes to generics. Is this a part of that criticism? The Remove and Add method of the data variable works just fine.
Upvotes: 2
Views: 250
Reputation: 147164
I note that the question has been edited such that the previous answers don't make much sense.
From looking at the question edits, it worth noting that if you want clients to see a method like:
public static void swapKundeData(List<?> data, int index1, int index2) {
But you want to implement:
public static <T> void swapKundeData(List<T> data, int index1, int index2) {
The wild card can be captured and a method with the client-friendly form can forward to an implementation-friendly form:
public static void swapKundeData(List<?> data, int index1, int index2) {
swapKundeDataImpl(data, index1, index2)
}
private static <T> void swapKundeDataImpl(List<T> data, int index1, int index2) {
(I'm assuming here that "kunde" is not a rude word.)
Upvotes: 1
Reputation: 418
Well for one, I would use
List<Kunde>
instead of
ArrayList<?>
since you are casting to Kunde anyway :).
Reason why it doesn't work is that you don't know the type of the objects passed. So if you set a Kunde that could possibly be the wrong type (since with ArrayList < ? > you can pass ArrayList < String > and setting a Kunde on that would be the wrong type).
Another possibility is:
private static <T> void swapData(List<T> data, int index1, int index2) {
T temporary = data.get(index1);
data.set(index1, data.get(index2)); //Does compile
data.set(index2, temporary); //Does compile
}
And to complete my rant, just use the swap method of Collections.
http://download.oracle.com/javase/1.4.2/docs/api/java/util/Collections.html#swap(java.util.List, int, int)
Upvotes: 6
Reputation: 15886
The problem was Eclipse.
I had not saved the file, so apparently nothing was recompiled.
Wow, I am really impressed of that IDE's incapabilities and annoyances, such as speed.
Oh well.
Upvotes: 0
Reputation: 346317
The reason for your problem is that you're declaring a type of ArrayList<?>
, which means "A list that should only contain a certain type, but I don't know which one". That has the consequence that the only thing you know about objects taken out of the list is that they're of type Object
because everything is (except primitives, which cannot be in a collection). But even more importantly, you cannot put anything into the list because you don't know to what type it is constrained.
This is why using the ?
wildcard is very rarely appropriate. In almost all cases you should either use a concrete type, or a named bounded type:
private static void swapKundeData(List<Kunde> data, int index1, int index2) {
Kunde temporary = data.get(index1);
data.set(index1, data.get(index2));
data.set(index2, temporary);
}
Note the use of the List
interface, which makes the code much more flexible about what it accepts.
private static <T> void swap(List<T> data, int index1, int index2) {
T temporary = data.get(index1);
data.set(index1, data.get(index2));
data.set(index2, temporary);
}
This is the really generic solution, which is typesafe, yet does not need to know what type the list elements are. You actually don't really gain any type safety by using Generics here (Object
would do just as well), but you could e.g. return one of the swapped elements and the compiler would know that the return value is the same type as the list's elements.
Upvotes: 1
Reputation: 19761
To summarize what Oli is saying, you can't assign to a collection of the "unknown type" '?' because java doesn't know what's supposed to go in there. However, since every "unknown type" is still an object, it's safe to call "getter" methods on it because they'll always return an object of type Object.
Upvotes: 0
Reputation: 272517
If you know that your ArrayList
contains Kunde
objects, then you should declare the method argument ArrayList<Kunde>
; there's no need to use a wildcard. And as you can see, it causes compile-time type errors.
See http://download.oracle.com/javase/tutorial/extra/generics/wildcards.html for the full explanation of the problem.
Upvotes: 2