I have the following code:
String test = "[{\"color\":\"red\"}]";
Class<? extends Base> baseObject = Base.class;
Collection<? extends Base> elements = new ArrayList<Base>();
if (test.startsWith("[")) {
elements.addAll(new ObjectMapper().readValue(test, Collection.class));
} else {
elements.add(new ObjectMapper().readValue(test, baseObject));
}
However I get on
elements.addAll(new ObjectMapper().readValue(test, Collection.class));
a compilation warning:
The expression of type Collection needs unchecked conversion to conform to Collection<? extends capture#1-of ? extends Base>
and for elements.add(new ObjectMapper().readValue(test, baseObject));
a compilation error:
The method add(capture#2-of ? extends Base) in the type Collection<capture#2-of ? extends Base> is not applicable for the arguments (capture#3-of ? extends Base)
What is wrong?
Error can be easily explained. Your collection is defined to hold instances of classes that extends Base. ObjectMapper.readValue is defined as following:
public <T> T readValue(JsonParser jp, Class<T> valueType)
This means that it returns instance of class specified as a second argument. If second argument is Collection.class this method returns Collection. Just Collection, not Collection<? extends Base> and not Collection<Base>. So, java compiler cannot be sure that you are going to put collection that contains correct objects into elements defined as Collection<? extends Base>. Moreover java syntax does not allow to supply as a parameter class with generics, i.e. you cannot call readValue(c, Collection<Base>.class).
The second case is more complicated. baseObject is defined as Class<? extends Base>. elements collection is defined as Class<? extends Base> too. So, what's the problem. The problem is in ?. The question mark means "something that extends Base". But these are 2 different "something" in both cases.
The solution can be either change definition of collection to Class<Base> or to use one class or method generic parameter in both cases, e.g.:
public <T extends Base> myMethod() {
Class<T> baseObject = Base.class;
Collection<T> elements = new ArrayList<T>();
elements.add(new ObjectMapper().readValue(test, baseObject));
}
Now both baseObject and elements use the same type T that indeed extends Base.
You can't add things to a collection with a wildcard type (that doesn't have an explicit lower bound using super, according to Brian; that does make some sense, as a subclass can always be cast to one of its superclasses, but I haven't used super-bounded wildcards much before so I'm not too sure of the details).
http://docs.oracle.com/javase/tutorial/extra/generics/wildcards.html
Specifically:
Since we don't know what the element type of c stands for, we cannot
add objects to it. The add() method takes arguments of type E, the
element type of the collection. When the actual type parameter is ?,
it stands for some unknown type. Any parameter we pass to add would
have to be a subtype of this unknown type. Since we don't know what
type that is, we cannot pass anything in. The sole exception is null,
which is a member of every type.
Type erasure is a... well, you know.
Related
When I created a instance of a class A and tried to access its getClass() method, its return type is different than what is mentioned in java Object class.
A a = new A() ;
Class<? extends A> clazz = a.getClass();
Even when I access the getClass method as mentioned above in Intellij, it says its return type is Class<? extends A> and even the java doc says it returns wildcard extends upper bound. I can totally accept it. Because I can create instance of B and reference to A and access getClass method.
But why does the return type of the getClass method is justClass<?> in the Object class
Edit 1 (After the comment from Andy Turner)
Class A {
List<?> returningNullList() {
return null;
}
}
When I create a instance of A , and tried to access returningNullList () method, it didn't give me return type as List<? extends A>. But when I tried to access getClass method it says return type is Class<? extends A> although the actual hard-coded return type is Class<? > in Object.java file
Is the getClass method is treated specially by compiler?
But why does the return type of the getClass method is justClass<?> in the Object class
Class<?> is the same as Class<? extends Object>, because all classes (except Object) have Object as a superclass. There's no reason to include that bound explicitly.
Read the documentation, i.e. the javadoc of getClass() in class Object:
The actual result type is Class<? extends |X|> where |X| is the erasure of the static type of the expression on which getClass is called. For example, no cast is required in this code fragment:
Number n = 0;
Class<? extends Number> c = n.getClass();
The bolding is from the javadoc, not added by me.
For class Object itself, it means that the return type is Class<? extends Object>, but since Class<?> is shorthand for Class<? extends Object>, the javadoc simply shows the shorthand.
Quoting the Java Language Specification, section 4.5.1. Type Arguments of Parameterized Types:
The wildcard ? extends Object is equivalent to the unbounded wildcard ?.
I need a custom method to check for a list containing an instance of a class and call this method but I do not understand this syntax "Class clazz" and I do not understand What's the second parameter of this method
public static <E> boolean containsInstanceOfOidInrArraylist(List<E> Arraylist, Class<? extends E> clazz) {
for (E e : Arraylist) {
if (clazz.isInstance(e)) {
return true;
}
}
return false;
}
Ok, so the first parameter of the function is a List<E> named Arraylist (You shouldn't capitalize variables in Java, name it as such arrayList).
The second parameter is a Class<? extends E> named clazz.
Check manub's explaination of Class<?>:
Class is a parameterizable class, hence you can use the syntax
Class<T> where T is a type. By writing Class<?>, you're declaring a
Class object which can be of any type (? is a wildcard). The Class
type is a type that contains meta-information about a class.
So now you know what Class<?> means, but what about Class<? extends E>?
<? extends E> basically means any class which extends E (or E itself).
So Class<? extends E> clazz means you have a varaible named clazz which is E class or a sub class of E.
See this tutorial: https://docs.oracle.com/javase/tutorial/java/generics/upperBounded.html
"Upper Bounded Wildcards
You can use an upper bounded wildcard to relax the restrictions on a variable. For example, say you want to write a method that works on List<Integer>, List<Double>, and List<Number>; you can achieve this by using an upper bounded wildcard.
To declare an upper-bounded wildcard, use the wildcard character ('?'), followed by the extends keyword, followed by its upper bound. Note that, in this context, extends is used in a general sense to mean either "extends" (as in classes) or "implements" (as in interfaces)."
The second parameter is a class that is the same as the class of the objects in the list, or extends it. clazz is used as a variable name because class is a reserved keyword and cannot be used.
I use Java 8. In my design a have a few simple classes which model value parameters such as FloatParameter or EnumParameter<E>. A have a common generic super class of these classes (GenericParameter<T>) which implements parameter name and its default value. The sub classes implement other attributes specific to them such as range in case of FloatParameter.
Moreover, I want to work with the types of the parameters regardless of their specific type. But I still want to bound the types in the way that they are sub types of GenericParameter<T>. In order to do that, I created a method such as process(Class<? extends GenericParameter<?>> paramType).
Now, the problem is that the EnumParameter.class cannot be assigned to a variable of type Class<? extends GenericParameter<?>> while FloatParameter.class can be.
Further I list the code for the classes to make it more clear and reproducible:
public class GenericParameter<T> {
protected String name;
protected T defaultValue;
}
public class FloatGenericParameter extends GenericParameter<Float> {
...
}
public class TypedGenericParameter<T> extends GenericParameter<T> {
...
}
Class<? extends GenericParameter<?>> fgpc = FloatGenericParameter.class; // ok
Class<? extends GenericParameter<?>> tgpc = TypedGenericParameter.class; // error: incompatible types: Class<TypedGenericParameter> cannot be converted to Class<? extends GenericParameter<?>>
Class<? extends GenericParameter> tgpc2 = TypedGenericParameter.class; // warning: [rawtypes] found raw type: GenericParameter
Finally, when using a non-generic base class, there is no problem:
public class Parameter {
....
}
public class FloatParameter extends Parameter {
...
}
public class TypedParameter<T> extends Parameter {
...
}
Class<? extends Parameter> fpc = FloatParameter.class; // ok
Class<? extends Parameter> tpc = TypedParameter.class; // ok
Please, do you have any suggestions?
I can go with process(Class<?> paramType) as a workaround or do casts, but I wanted to benefit from the static type checking by the compiler.
EDIT:
I would like to use the cast when registering factories that produce GUI components for each parameter type. The code looks like:
addParameterComponentFactory(EnumParameter.class, new ParameterComponentFactory() { ... })
In such case, the compiler would check the added parameter type at compile time. Also the code would be more self-explaining.
EDIT 2:
Currently, I am using the suggested approach to introduce a type parameter for the addParameterComponentFactory method. The signature looks like this:
public static <P extends GenericParameter<?>> addParameterComponentFactory(Class<P> clazz, ParameterComponentFactory pcf)
With this definition I am able to specify TypedParameter.class (EnumParameter.class - also one type param) as well as I obtain the static type checking.
Let's start with the core bits of your API. You have a generic Parameter<T>
type that represents some named parameter with a value of type T. You have
specialized GUI components designed to edit or display specific types of
parameters, and you want to be able to register factories to create these
components.
class Parameter<T> {
String name;
T defaultValue;
}
class ParameterComponent<P extends Parameter> {
void setParameter(final P p) {}
}
interface ParameterComponentFactory<P extends Parameter> {
ParameterComponent<P> newComponent();
}
class FloatParameter extends Parameter<Float> {}
class FloatParameterComponent extends ParameterComponent<FloatParameter> {}
class EnumParameter extends Parameter<Enum> {}
class EnumParameterComponent extends ParameterComponent<EnumParameter> {}
If I understand you correctly, you're running into trouble figuring out how to
declare a method that statically enforces a relationship between some
Parameter type and a factory for GUI components specialized for that type.
For example, you want to be able to write this:
addComponentFactory(EnumParameter.class, EnumParameterComponent::new); // OK
addComponentFactory(FloatParameter.class, FloatParameterComponent::new); // OK
addComponentFactory(FloatParameter.class, EnumParameterComponent::new); // ERROR!
The problem is related to the rules of generic subtyping, and you can work around them by employing a type variable instead of an embedded wildcard. This should give you the type checking you want, without the need for
nasty casting:
static <P extends Parameter> void addComponentFactory(
final Class<P> parameterType,
final ParameterComponentFactory<? extends P> factory) { ... }
Explanation[1]
Explain the difference between introducing a new type P extends Parameter<?> used in Class<P> and stating
directly Class<? extends Parameter<?>>
This is complicated, so bear with me. Let's talk a bit about wildcards, raw
types, and conversions. Consider the following:
// Scenario 1(a)
GenericParameter raw = /* some value */;
GenericParameter<?> wc = raw;
// Scenario 1(b)
Class raw = GenericParameter.class;
Class<?> wc = raw;
// Scenario 2
Class<GenericParameter> classOfRaw = GenericParameter.class;
Class<GenericParameter<?>> classOfWC = classOfRaw;
Scenarios 1(a) and 1(b) both compile for the same reason: because a raw type
G may undergo an unchecked conversion
to any parameterized type of the form G<T_1, ..., T_n>.
Scenario 2 does NOT compile. But why?
In Scenario 2, neither side in the second assignment is a raw type. For the
assignment to be valid,
there must be either an identity conversion or a widening conversion
from the right-hand type to the left-hand type. For widening conversions on
reference types, the left-hand type must be a supertype of the right-hand type.
When these types are generic, the rules of generic subtyping
apply. Specifically, the type arguments on the left-hand side must
contain
the type arguments on the right-hand side.
An assignment from Class<String> to Class<? extends Object> is valid.
Class<String> is a generic subtype of Class<? extends Object> because
? extends Object contains String. In Scenario 2, for the second
assignment to be valid, GenericParameter<?> would have to contain
GenericParameter, but it doesn't. T is not a subtype of T<?>;
T is a supertype of T<?>. Thus, by the generic subtyping rules,
Class<T> is not a subtype of Class<T<?>>, and the assignment is not
valid.
So why does the following work?
public static <P extends GenericParameter<?>> addParameterComponentFactory(
Class<P> clazz,
ParameterComponentFactory pcf)
addParameterComponentFactory(EnumParameter.class, new ParameterComponentFactory() {})
In the call above, type inference on P is driven entirely by the
Class<P> argument. You are passing a Class<EnumParameter>, so P
in this case gets bound to the raw type EnumParameter. For the constraint
P extends GenericParameter<?> to be satisfied, GenericParameter<?>
must be assignable from EnumParameter, and it is assignable via an
unchecked conversion, just like in Scenarios 1(a) and 1(b).
[1] This explanation is blatant plagarism
an amalgamation of other excellent Stack Overflow answers, mostly by
radiodef.
The problem is in a generic restriction:
public List<Class<? extends Annotation>> getAnnotations() {
return new ArrayList<>(Arrays.asList(Override.class));
}
Real return type is ArrayList<Class<Override>>
Method expects List<Class<? extends Annotation>>
Class<Override> is a subtype of Class<? extends Annotation>
Class<? extends Annotation> c = Override.class; //allowed
ArrayList is a subtype of a List, if types of the elements match:
List<? extends Number> l = new ArrayList<Integer>(); // allowed
However, this is not allowed:
List<Class<? extends Annotation>> l = Arrays.asList(Override.class);
List<Class<? extends Annotation>> l = new ArrayList<>(Arrays.asList(Override.class));
Is it even possible or Class wildcards are broken?
I would assume that this is because of the jdk 1.7 type inference nature.
As you may already know, the Arrays.asList(T ... elems) method is generic, but we seldom explicitly specify the type-parameter which we'd like the method to work with and thus we rely on the type inference feature of the compiler.
So, when the compiler sees an Arrays.asList(Override.class) statement it will infer that the type-parameter for the method should be replaced with Class<Override>, i.e. we'd have a version of the method in this form:
public List<Class<Override>> asList(Class<Override> ... elems)
However, if you explicitly set the type parameter for the method to
List<Class<? extends Annotation>> l =
Arrays.<Class<? extends Annotation>>asList(Override.class);
then the compiler will actually know what the type-parameter has to be replaced with and then the version of the .asList() method would be:
public List<? extends Annotation> asList(Class<? extends Annotation> ... elems)
Now this will compile fine, since Class<? extends Annotation> is compatible to Class<Override>. In Java8, the type inference feature is improved even more, so that you don't have to explicitly set the type-parameter for the .asList() method.
However, the more interesting question goes to
Why List<Class<Override>> is not compatible with List<Class<? extends Annotation>>?
The java.lang.Class is a final one, which would help answering the following two questions, the combination of which will answer the above question. :)
So,
What does a List<Class<Override>> mean?
List<Class<Override>> means that we can add only instances of Class<Override> and nothing else to the list. Which is great, knowing that we can't even add Class<Override> sub-classes, since the Class type is final.
What does a List<Class<? extends Annotation>> mean?
This type of List represents a whole family of lists of classes, all of which are subclasses of the Annotation type, which means that we can successfully add any annotation type (for example, SuppressWarnings.class, Override.class, Documented.class, etc.) to the list.
Lets assume that the following example was actually correct:
List<Class<Override>> overrides = Arrays.asList(Override.class);
List<Class<? extends Annotation>> annotations = new ArrayList<>();
annotations = overrides;
annotations.add(SuppressWarnings.class); //HUGE PROBLEM
annotations.add(Documented.class); //ANOTHER HUGE PROBLEM
The two huge problems come from the fact that we're trying to add some non-Override instances to the overrides, which is very wrong.
We have smart enough compiler that can actually detect such possible problems and throwing a compile-time error is the way to prevent us from doing this.
More info:
What do multi-level wildcards mean?
Is List<Dog> a subclass of List<Animal>?
ArrayList is a subtype of a List, if types of the elements match:
List<? extends Number> l = new ArrayList<Integer>(); // allowed
Yes, but in your example the element types do not match:
List<Class<? extends Annotation>> l = new ArrayList<Class<Override>>();
Granted, Class<Override> is a subtype of Class<? extends Annotation>, but just like List<String> is not a subtype of List<Object>, List<Class<Override>> is not a subtype of List<Class<? extends Annotation>>. It would be a subtype of List<? extends Class<? extends Annotation>>, though.
That said, the reason your code does not compile is that in Java 7, type inference does not take into account the method's return type when inferring the type of a return statement's expression, so it defaults to the most specific type that could be assigned to
Arrays.asList(Override.class)
not realizing that the return statement would only compile with a more flexible type (Java 8 type inference is smarter, btw). One workaround is to explicity specify the type argument:
Arrays.<Class<? extends Annotation>(Override.class);
or give Java 7's type inference a hint by assigning to a local variable first:
List<Class<? extends Annotation>> list = Arrays.asList(Override.class);
return list;
or change the method return type to
List<? extends Class<? extends Annotation>> getAnnotations()
so the inferred type does not matter.
I want to know what is the usage of having such syntax. I have written a simple program as below,
public class Sample{
public static void main(String[] args) {
Class<? extends Collection> someCollectionClass = someMethod();
}
public static ArrayList someMethod() {
return new ArrayList();
}
}
Why it shows compilation error as,
- Collection is a raw type. References to generic type Collection<E> should be
parameterized
- Type mismatch: cannot convert from ArrayList to Class<? extends Collection>
In here does that Class expect a class (Its actually the object that it accept know, Is it?) which does extends the Collection. So whats wrong with ArrayList?
Also is it a valid if syntax if i declare something as Class<? extends T>
Because ArrayList is not a Class. Perhaps you mean someMethod().getClass()?
The first error message stems from the type parameter in your declaration:
Class<? extends Collection> someCollectionClass = someMethod();
The type Collection is what is called a "raw type" in Java, because the interface Collection takes a type parameter, but none is given in the declaration. The same applies to the unadorned use of ArrayList.
However, The declaration doesn't actually do what I guess you think it does... You actually declare a variable named someCollectionClass, to which you can assign instances of type Class<? extends Collection>, i.e., (reflection) class descriptors (of a particular type). The second error message is the compiler complaining about that: an instance of type ArrayList (returned by someMethod) cannot be assigned to a variable, whose type is declared as "allow only instances of Class<...> (which is a special Java run-time type describing classes).
Collection someCollection = someMethod();
someMethod is returning an instance of type List, you are trying to assign it to a variable which is expecting the Collection class not an instance. The following code should work.
Collection someCollectionClass = someMethod();