I have the following member in my class:
List<? extends SomeObject> list;
When I try to do:
list.add(list.get(0));
I get:
Test.java:7: error: no suitable method found for add(CAP#1)
list.add(list.get(0));
^
method Collection.add(CAP#2) is not applicable
(argument mismatch; Object cannot be converted to CAP#2)
method List.add(CAP#2) is not applicable
(argument mismatch; Object cannot be converted to CAP#2)
where CAP#1,CAP#2 are fresh type-variables:
CAP#1 extends Object from capture of ? extends Object
CAP#2 extends Object from capture of ? extends Object
My question is twofold:
Why doesn't it compile? Why can't I pass get()'s result to add()?
And how can I achieve this in another way without resorting to casting?
I understand that in a method with <T extends SomeObject> I can't just say:
T someObject = list.get(0);
list.add(someObject);
since my T could be another extension than the ? extension.
I also understand I can't say:
List<? extends SomeObject> list1;
List<? extends SomeObject> list2;
list1.add(list2.get(0));
But since the add and the get should work with the same generic type in list.add(list.get(0)) I don't understand why the compiler doesn't accept it.
What I really need is
[something of type T where T is whatever was used to instantiate list] someObject = list.get(0);
list.add(someObject);
so that I can later
list.add(someObject);
I don't think I should have to template my whole class to achieve this, should I?
class MyClass<T extends SomeObject> {
List<T> list;
and then later a method with
T someObject = list.get(0);
of course works, but screws other parts of my code.
So the first question is why doesn't this work, second question is what's the best workaround?
My question is twofold, why can't I do:
list.add(list.get(0));
Because the compiler isn't smart enough to know that you're adding something from list back into list. The compiler doesn't consider list.get(0) to have anything to do with list once it is evaluated: it's just "some expression" of type ? extends SomeObject.
To solve this, add a method with its own type variable:
private <T> void addFirst(List<T> list) {
list.add(list.get(0));
}
and replace the original list.add(list.get(0)); with an invocation of this:
addFirst(list);
This only defines a type variable on the method, and does not need to be visible outside the class, so you don't need a class-level type variable.
It's perhaps worth pointing out this is analogous to the Collections.swap method: that's using set rather than add, but, from a generics point of view, it's the same thing:
#SuppressWarnings({"rawtypes", "unchecked"})
public static void swap(List<?> list, int i, int j) {
// instead of using a raw type here, it's possible to capture
// the wildcard but it will require a call to a supplementary
// private method
final List l = list;
l.set(i, l.set(j, l.get(i)));
}
This takes an approach which is technically type-safe, and does avoid casts; but it's a bit gross, because it uses raw types.
I would imagine that it is only like this for backwards-compatibility reasons. Given a chance to write it again, you could just define a type variable as in the addFirst method above.
When use wildcards, we should follow The Get and Put Principle which introduced in Java Generics and Collections:
The Get and Put Principle: use an extends wildcard when you only get values out of a
structure, use a super wildcard when you only put values into a structure, and don’t use
a wildcard when you both get and put.
In your case, don't use a wildcard as you both get element from list and put element to list.
Related
I have read Get type of a generic parameter in Java with reflection post and it made me wonder how that would be possible. I used the solution that someone posted and using the code
List<Integer> l = new ArrayList<>();
Class actualTypeArguments = (Class) ((ParameterizedType) l.getClass().getGenericSuperclass()).getActualTypeArguments()[0];
This, however does not work for me, resulting in
java.lang.ClassCastException: sun.reflect.generics.reflectiveObjects.TypeVariableImpl cannot be cast to java.lang.Class
If I remove the class cast, the type of the actual argument is E, which is the type definition from List interface.
My question is, therefore, am I doing something wrong here? This behaviour is something I would have expected anyway, since the types are supposed to be erased during compile time, correct?
The code you use only works in some very specific cases, where the actual type parameter is known (and stored) at compile time.
For example if you did this:
class IntegerList extends ArrayList<Integer> {}
List<Integer> l = new IntegerList();
In this case the code you showed would actually return Integer.class, because Integer is "baked into" the IntegerList.
Some libraries (ab)use this trick via the use of type tokens. See for example the GSON class TypeToken:
Represents a generic type T. You can use this class to get the generic type for a class. > For example, to get the generic type for Collection<Foo>, you can use:
Type typeOfCollectionOfFoo = new TypeToken<Collection<Foo>>(){}.getType()
This works because the anonymous class created in here has compiled-in the information that its type parameter is Collection<Foo>.
Note that this would not work (even if the TypeToken class wouldn't prevent it by making its constructor protected):
Type typeOfCollectionOfFoo = new TypeToken<Collection<Foo>>().getType()
The javadoc will tell you what you are doing.
Class#getGenericSuperclass() states
Returns the Type representing the direct superclass of the entity
(class, interface, primitive type or void) represented by this Class.
If the superclass is a parameterized type, the Type object returned
must accurately reflect the actual type parameters used in the source
code. [...]
The direct superclass of ArrayList is AbstractList. The declaration is as such in the source code
public class ArrayList<E> extends AbstractList<E>
implements List<E>, RandomAccess, Cloneable, java.io.Serializable
So if you print out the Type object returned by it, you will see
java.util.AbstractList<E>
and therefore ParameterizedType#getActualTypeArguments() which states
Returns an array of Type objects representing the actual type
arguments to this type.
will return the Type
E
since E is the actual type argument used in the ArrayList class definition.
The method you described does ONLY work, when the Generic Type is Set due to inheritance, because then its known during compile time:
public class SomeClass<T>{
}
public class SpecificClass extends SomeClass<String>{
}
For this example, you can use the method and you'll get back "String.class".
If you are creating instances on the fly it won't work:
SomeClass s = new SomeClass<String>(); //wont work here.
Some common work around is, to pass the actual class as a parameter for later reference:
public class SomeClass<T>{
Class<T> clazz
public SomeClass(Class<T> clazz){
this.clazz = clazz;
}
public Clazz<T> getGenericClass(){
return this.clazz;
}
}
usage:
SomeClass<String> someClass= new SomeClass<String>(String.class);
System.out.println(someClass.getGenericClass()) //String.class
Actually you don't even need the Generic type for such an scenario, because Java would do the same thing, as if you would handle the "T" as Object. Only advantage is, that you can define getter and Setter of T and don't need to typecast Objects all the time. (Because Java is doing that for you)
(It's called Type Erasure)
I have class:
public class WebDriverHighlighterListener extends AbstractWebDriverEventListener implements WebDriverEventListener {
And code
Why does it demand implicit type when I have constructor with wildcard?
There are two different issues. Before Java 8, the expression Arrays.asList(X) invariably has the type List<TypeOfX> which you refer to as “implicit type”.
This type is not assignment compatible with your wildcard.
Let’s explain it with a simple example. Suppose, we declare a variable of type
List<Class<String>> list=Arrays.asList(String.class);
This is a list, capable of holding instances of type Class<String> (there is only one, i.e. String.class) and nothing else.
In contrast, a list of type
List<Class<? extends CharSequence>> list2;
is allowing us to do all of these:
list2.add(StringBuilder.class);
list2.add(String.class);
list2.add(CharBuffer.class);
therefore, it should be clear, that we can’t assign list to list2 as then a list, allowing only String.class as it’s element, could suddenly get filled with these other Class<? extends CharSequence> objects.
If you want to have list, guaranteeing that the instances you will retrieve from it are of type Class<? extends CharSequence>, without constraining its actual type, i.e. being assignment compatible with List<Class<String>>, because you are not going to store new elements to the list, you can use
List<? extends Class<? extends CharSequence>> list3=list;// legal assignment
which allows
Class<? extends CharSequence> cl=list3.get(0);
but attempts to store new elements to list3 will be rejected by the compiler, because the actual element type of is unknown (Well, except for attempts to store null as it is legal for all reference types).
Alternatively you can use
List<Class<? extends CharSequence>> list4=Collections.unmodifiableList(list);
Because, it is known that the returned list will reject modifications at runtime, this kind of type conversion is accepted at compile-time.
Of course, you can also change the type of the Array.asList expression. This is the right way to go, when you are going to modify the list.
List<Class<? extends CharSequence>> list
= Arrays.<Class<? extends CharSequence>>asList(String.class);
Starting with Java 8, this type will get inferred automatically using the target type, thus the following is legal Java 8 code:
List<Class<? extends CharSequence>> list=Arrays.asList(String.class);
This also works when the Array.asList expression is an argument to a constructor invocation.
This all applies to AbstractWebDriverEventListener and WebDriverEventListener the same way it applies to String and CharSequence.
Given the following example (using JUnit with Hamcrest matchers):
Map<String, Class<? extends Serializable>> expected = null;
Map<String, Class<java.util.Date>> result = null;
assertThat(result, is(expected));
This does not compile with the JUnit assertThat method signature of:
public static <T> void assertThat(T actual, Matcher<T> matcher)
The compiler error message is:
Error:Error:line (102)cannot find symbol method
assertThat(java.util.Map<java.lang.String,java.lang.Class<java.util.Date>>,
org.hamcrest.Matcher<java.util.Map<java.lang.String,java.lang.Class
<? extends java.io.Serializable>>>)
However, if I change the assertThat method signature to:
public static <T> void assertThat(T result, Matcher<? extends T> matcher)
Then the compilation works.
So three questions:
Why exactly doesn't the current version compile? Although I vaguely understand the covariance issues here, I certainly couldn't explain it if I had to.
Is there any downside in changing the assertThat method to Matcher<? extends T>? Are there other cases that would break if you did that?
Is there any point to the genericizing of the assertThat method in JUnit? The Matcher class doesn't seem to require it, since JUnit calls the matches method, which is not typed with any generic, and just looks like an attempt to force a type safety which doesn't do anything, as the Matcher will just not in fact match, and the test will fail regardless. No unsafe operations involved (or so it seems).
For reference, here is the JUnit implementation of assertThat:
public static <T> void assertThat(T actual, Matcher<T> matcher) {
assertThat("", actual, matcher);
}
public static <T> void assertThat(String reason, T actual, Matcher<T> matcher) {
if (!matcher.matches(actual)) {
Description description = new StringDescription();
description.appendText(reason);
description.appendText("\nExpected: ");
matcher.describeTo(description);
description
.appendText("\n got: ")
.appendValue(actual)
.appendText("\n");
throw new java.lang.AssertionError(description.toString());
}
}
First - I have to direct you to http://www.angelikalanger.com/GenericsFAQ/JavaGenericsFAQ.html -- she does an amazing job.
The basic idea is that you use
<T extends SomeClass>
when the actual parameter can be SomeClass or any subtype of it.
In your example,
Map<String, Class<? extends Serializable>> expected = null;
Map<String, Class<java.util.Date>> result = null;
assertThat(result, is(expected));
You're saying that expected can contain Class objects that represent any class that implements Serializable. Your result map says it can only hold Date class objects.
When you pass in result, you're setting T to exactly Map of String to Date class objects, which doesn't match Map of String to anything that's Serializable.
One thing to check -- are you sure you want Class<Date> and not Date? A map of String to Class<Date> doesn't sound terribly useful in general (all it can hold is Date.class as values rather than instances of Date)
As for genericizing assertThat, the idea is that the method can ensure that a Matcher that fits the result type is passed in.
Thanks to everyone who answered the question, it really helped clarify things for me. In the end Scott Stanchfield's answer got the closest to how I ended up understanding it, but since I didn't understand him when he first wrote it, I am trying to restate the problem so that hopefully someone else will benefit.
I'm going to restate the question in terms of List, since it has only one generic parameter and that will make it easier to understand.
The purpose of the parametrized class (such as List<Date> or Map<K, V> as in the example) is to force a downcast and to have the compiler guarantee that this is safe (no runtime exceptions).
Consider the case of List. The essence of my question is why a method that takes a type T and a List won't accept a List of something further down the chain of inheritance than T. Consider this contrived example:
List<java.util.Date> dateList = new ArrayList<java.util.Date>();
Serializable s = new String();
addGeneric(s, dateList);
....
private <T> void addGeneric(T element, List<T> list) {
list.add(element);
}
This will not compile, because the list parameter is a list of dates, not a list of strings. Generics would not be very useful if this did compile.
The same thing applies to a Map<String, Class<? extends Serializable>> It is not the same thing as a Map<String, Class<java.util.Date>>. They are not covariant, so if I wanted to take a value from the map containing date classes and put it into the map containing serializable elements, that is fine, but a method signature that says:
private <T> void genericAdd(T value, List<T> list)
Wants to be able to do both:
T x = list.get(0);
and
list.add(value);
In this case, even though the junit method doesn't actually care about these things, the method signature requires the covariance, which it is not getting, therefore it does not compile.
On the second question,
Matcher<? extends T>
Would have the downside of really accepting anything when T is an Object, which is not the APIs intent. The intent is to statically ensure that the matcher matches the actual object, and there is no way to exclude Object from that calculation.
The answer to the third question is that nothing would be lost, in terms of unchecked functionality (there would be no unsafe typecasting within the JUnit API if this method was not genericized), but they are trying to accomplish something else - statically ensure that the two parameters are likely to match.
EDIT (after further contemplation and experience):
One of the big issues with the assertThat method signature is attempts to equate a variable T with a generic parameter of T. That doesn't work, because they are not covariant. So for example you may have a T which is a List<String> but then pass a match that the compiler works out to Matcher<ArrayList<T>>. Now if it wasn't a type parameter, things would be fine, because List and ArrayList are covariant, but since Generics, as far as the compiler is concerned require ArrayList, it can't tolerate a List for reasons that I hope are clear from the above.
It boils down to:
Class<? extends Serializable> c1 = null;
Class<java.util.Date> d1 = null;
c1 = d1; // compiles
d1 = c1; // wont compile - would require cast to Date
You can see the Class reference c1 could contain a Long instance (since the underlying object at a given time could have been List<Long>), but obviously cannot be cast to a Date since there is no guarantee that the "unknown" class was Date. It is not typsesafe, so the compiler disallows it.
However, if we introduce some other object, say List (in your example this object is Matcher), then the following becomes true:
List<Class<? extends Serializable>> l1 = null;
List<Class<java.util.Date>> l2 = null;
l1 = l2; // wont compile
l2 = l1; // wont compile
...However, if the type of the List becomes ? extends T instead of T....
List<? extends Class<? extends Serializable>> l1 = null;
List<? extends Class<java.util.Date>> l2 = null;
l1 = l2; // compiles
l2 = l1; // won't compile
I think by changing Matcher<T> to Matcher<? extends T>, you are basically introducing the scenario similar to assigning l1 = l2;
It's still very confusing having nested wildcards, but hopefully that makes sense as to why it helps to understand generics by looking at how you can assign generic references to each other. It's also further confusing since the compiler is inferring the type of T when you make the function call (you are not explicitly telling it was T is).
The reason your original code doesn't compile is that <? extends Serializable> does not mean, "any class that extends Serializable," but "some unknown but specific class that extends Serializable."
For example, given the code as written, it is perfectly valid to assign new TreeMap<String, Long.class>() to expected. If the compiler allowed the code to compile, the assertThat() would presumably break because it would expect Date objects instead of the Long objects it finds in the map.
One way for me to understand wildcards is to think that the wildcard isn't specifying the type of the possible objects that given generic reference can "have", but the type of other generic references that it is is compatible with (this may sound confusing...) As such, the first answer is very misleading in it's wording.
In other words, List<? extends Serializable> means you can assign that reference to other Lists where the type is some unknown type which is or a subclass of Serializable. DO NOT think of it in terms of A SINGLE LIST being able to hold subclasses of Serializable (because that is incorrect semantics and leads to a misunderstanding of Generics).
I know this is an old question but I want to share an example that I think explains bounded wildcards pretty well. java.util.Collections offers this method:
public static <T> void sort(List<T> list, Comparator<? super T> c) {
list.sort(c);
}
If we have a List of T, the List can, of course, contain instances of types that extend T. If the List contains Animals, the List can contain both Dogs and Cats (both Animals). Dogs have a property "woofVolume" and Cats have a property "meowVolume." While we might like to sort based upon these properties particular to subclasses of T, how can we expect this method to do that? A limitation of Comparator is that it can compare only two things of only one type (T). So, requiring simply a Comparator<T> would make this method usable. But, the creator of this method recognized that if something is a T, then it is also an instance of the superclasses of T. Therefore, he allows us to use a Comparator of T or any superclass of T, i.e. ? super T.
what if you use
Map<String, ? extends Class<? extends Serializable>> expected = null;
Im supposed to make a method that returns the max value of any list, I guess this is a generic method. But I dont understand the parameters, could anyone please explain me?
Also I made a iterator that i will use in the solution to run through the list, but when i make a instance of the iterator this method gives me the following error: "#nameofclass can not be referenced from a static context", then how do I make a instance here? ( its supposed to be static for some reason) I would appreciate any help!
public static <T> int maks(List<T> list, Comparator<? super T> c)
{
// return max in a list
}
The following is a pretty typical generic method declaration:
public static <T> int max(List<T> list, Comparator<? super T> c) {
:
:
}
There are two overall kinds of generic declarations: 1) generic class/interface, and 2) generic method. Once you're comfortable with these two idioms, you're well on your way to having a good understanding of generics. The raw type declaration for this is:
public static int max(List list, Comparator c) {
:
:
}
The raw type declaration makes it easy to see that this method returns a value to its caller of type int. The method accepts two parameters: a List instance and a Comparator instance.
The trouble with the raw type declaration is that it is not safe. Why? Because both List<E> and Comparator<T> are generic classes that have been defined with a formal generic type parameter. If you use a generic class, but then don't specify its parameter (as in the declaration above) you lose all the type safety and expressiveness that generics provide for you.
A generic method is characterized by the following method:
public <T> MyType myMethodName( /* parameters */) { ... }
Notice that a generic method is declared with its type parameters in the method declaration and that the type parameters come immediately before the return type. This is standard.
In this case <T> indicates an unbounded type parameter for your method. Wherever T appears in your method, the actual type parameter passed to your method will take the place of T. It is common, but not necessary, to make the method parameters depend upon T (but T can appear anywhere inside the method body that a type declaration can appear -- with some exceptions necessitated by type erasure).
In your example, the parameters list is ...
(List<T> list, Comparator<? super T> c)
The first parameter specified that the instance list passed to your method will have the type List. Because T is the generic method type parameter listed in your method declaration, you can imagine that it is substituted for the actual type parameter that was passed to your method, eg. List<String> list.
The second parameter is a bit more complex. It is a bounded wildcard type parameter. The sematics for ? are "any type" and the semantics for super are "any class that is the same class or a super class of". Therefore the second parameter reads as "any type that is the same type or a super type of the actual type parameter T that was passed to your method."
There is a mnemonic that is apt for bounded wildcard types: PECS. Producer extends, Consumer super. Comparators are always consumers of their instances, and so the right way to specify them in a parameter list is as shown in your method declaration.
You have List list and Comparator c, so why not just:
Collections.max(list, c);
-it will return max element in a List or any other Collection.
Though I don't understand why you want to return int when looking for max value in a generic list -maybe you're looking for its' index?
It is a pretty simple one. I want to declare a list of objects, but I want make sure all objects implemented the Comparable interface. What should I do? I try to write
List<Comparable> heap = new ArrayList<Comparable>();
But compiler gives me a warning. What is the proper way to write it?
Thanks
Follow up:
I thought I had finished the question before I post it but apparently I didn't. So let me finish it up.
My purpose is to have a list of objects that:
Implements the Comparable interface
Are all with the same type
Can I make it
List<Comparable<?>> heap = new ArrayList<Comparable<?>>()
No, I can't. The reason is because I need to retrieve the elements from the list and compare them. like:
if( heap.get(0).compareTo(heap.get(1)) > 0)
If I use wildcard List<Comparable<?>>, the complier will give me an error. Saying heap.get(0) cannot match heap.get(1) So I need to know the correct way to declare it.
I find somebody asking me what the warning is.... that surprises me.....well, the warning is:
Comparable is a raw type. References to generic type Comparable should be parameterized
It's because you're using the raw type Comparable. You can try giving Comparable a wildcard type parameter:
List<Comparable<?>> heap = new ArrayList<Comparable<?>>();
If you want the objects to all be of the same type, you can do something along the lines of
public static <T extends Comparable<? super T>> List<T> getList() {
...
}
and return your list from getList().
Since all your objects are of the same type (let's say f.e. FooType), then just use a List<FooType>.
Perhaps you could write a method that only takes a type that extends Comparable and returns a List of that type:
public <T extends Comparable> List<T> getComparableList(T t) {
List<T> heap = new ArrayList<T>();
return heap;
}