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();
Related
Hi all i am learning Generics in Java. in which i have created this hierarchy.
Now i have created a LivingThing class
public class LivingThing<T extends LivingThingTypes> implements Iterable<LivingThingTypes>{
public ArrayList<T> create(Class<T> type) {
ArrayList arrayList = new ArrayList<>();
for (T item : list) {
if (item.getClass().equals(type)) {
arrayList.add(item);
}
}
return arrayList;
}
}
So when i try to access create() method like this code of section it doesn't works.
livingList.create(Human.class).size();
livingList.create(Cat.class).size();
livingList.create(Hen.class).size();
But if i change method into this it works perfectly
public class LivingThing<T extends LivingThingTypes> implements Iterable<LivingThingTypes>{
public <V extends LivingThingTypes>ArrayList<V> create(Class<V> type) {
ArrayList arrayList = new ArrayList<>();
for (T item : list) {
if (item.getClass().equals(type)) {
arrayList.add(item);
}
}
return arrayList;
}
}
The important thing about generics is that they are invariant. This means in your case that even though Human class extends LivingThingTypes but List<Human> doesn't extend List<LivingThingTypes>. So basically you can't do the following assignment:
List<Human> list1;
List<LivingThingTypes> list2 = list1; //compile error
That's how Generics are designed. The reason is imaging you have a Animal parent class and Dog and Cat as child classes. Now you created a List<Dog> and assigned it to List<Animal>. Now Since Animal is parent class of Cat also you can add cats to List<Animal>. Wile iterating it may give ClassCastException. Now the basic pros of using Generics is they provide Type safety but getting ClassCastException means that is not the case and thus the Generics are invariant.
But when you use extends along with Type parameter then it allows the assignment but then you have to remember PECS(Producer Extends and Consumer Super).
In your first case you have Type Parameter declared at class level. Now when you create instance of LivingThing class you have to mention the type parameter like LivingThing<LivingThingTypes> livingList = new LivingThing();. And that becomes the value of T. Now the compiler will expect you to send the same Type inside create method also because of the reason I mentioned in the earlier para.
In your second case you are creating a new Type parameter which is bound to the method only and here you are telling it that V extends LivingThingType and thus now Class<V> type argument of create method can accept Human.class/Hen.class/Cat.class. You can use the same Type parameter T also in place of V but to avoid confusion you should name them differently as you have done.
That was not working because of this concept defined in Java-Oracle-Docs.
(As Java Doc Says)
Given two concrete types A and B (for example, Number and Integer), MyClass has no relationship to MyClass, regardless of whether or not A and B are related. The common parent of MyClass and MyClass is Object.
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.
I'm writing generic class
public class SomeClass<T> {
public static <T extends Comparable<? super T>> T min(Collection<? extends T> c) {
T min = c.iterator().next();
for (T element : c)
if (element.compareTo(min) < 0)
min = element;
return min;
}
}
public class Main {
public static void main(String[] args) {
SomeClass<Integer>.min(Arrays.asList(1, 2, 3)); // compile-time error
SomeClass.min(Arrays.asList(1, 2, 3)); // ok
}
}
In generic class SomeClass and generic method SomeMethod type-parameter T is the same or defference?
Why we have compile time-error on the string SomeClass<Integer>.min(Arrays.asList(1,2,3));?
The class declaration
public class SomeClass<T>
defines a generic class, where <T> specifies the type parameter (also called type variable). This introduces the type variable, T, that can be used anywhere inside the class.
And the method declaration:
public static <T extends Comparable<? super T>> T min(Collection<? extends T> c) {
...
}
defines a generic method. Generic methods are methods that introduce their own type parameters. This is similar to declaring a generic type, but the type parameter's scope is limited to the method where it is declared.
Now if you want to call the generic method min, you need to call:
SomeClass.<Integer>min(Arrays.asList(1,2,3));
It's different, and you should never write code like this, specifically because of the possibility for confusion. Always use different type variables on classes and methods inside those classes.
T is for Type and you are accessing static method which has nothing to do with T.
Either use like this
SomeClass<Integer> a = new SomeClass<Integer>();
a.min(Arrays.asList(1, 2, 3));
OR
SomeClass.min(Arrays.asList(1, 2, 3));
The two Ts are different: the fist one is a parameter for the class (and is unused) and the second one is specific to the method. Since the method is static, the class parameter doesn’t affect it.
When you write SomeClass<Integer>.min(Arrays.asList(1, 2, 3));, you get an error because it doesn’t make sense to add a parameter to SomeClass since no object of that class is instanciated. SomeClass is only used to tell the compiler that you want to call a static method from that class. You can add a parameter to the method with SomeClass.<Integer>min(Arrays.asList(1, 2, 3));, but you don't have to since the compiler can infer the type here.
So what the compile message told you was that it's a syntax error. Why it's invalid syntax is easy to understand. You are trying to call a method on a type. That means you are calling a static method. Static methods are not within the scope of generic type parameters. So it is not allowed to put a generic type argument on the left side.
If you want the technical reason, it's because your method call expression is not one of the forms that's allowed by the syntax. The closest form to yours is TypeName . NonWildTypeArguments Identifier ( ArgumentListopt ). But TypeName (which is defined here) must be an identifier or package-qualified identifier. It does not allow brackets.
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.
Say I have a parent interface/class like so
interface Parent<T> {}
And a number of implementing interfaces that fix the generic type.
interface Child extends Parent<Type> {}
Can I use reflection to get the instance of Class representing T if I have the Class object for Child. Something like this:
<T, I extends Parent<T>> I create(Class<I> type) {
Class<T> tType = ...
...
}
Currently I'm having tType be passed in as a parameter, but I'd like to simplify things if I can.
Yes, despite what the others have said, this info is available if you have access to the subclass' Class object. You need to use getGenericSuperclass along with getActualTypeArguments.
ParameterizedType superClass = (ParameterizedType)childClass.getGenericSuperclass();
System.out.println(superClass.getActualTypeArguments()[0]);
In your example, the "actual" type argument should return the Class for Type.
If you need to do anything non-trivial with generic types at runtime, consider Guava's TypeToken. It can answer your question (and many more!) while addressing some of the nuanced concerns raised by commenters:
private interface Parent<T> {}
private interface Intermediate<U, V> extends Parent<V> {}
private interface Child<Z> extends Comparable<Double>, Intermediate<Z, Iterable<String>> {}
public void exploreGuavaTypeTokens() {
final TypeToken<? super Child> token = TypeToken.of(Child.class).getSupertype(Parent.class);
final TypeToken<?> resolved = token.resolveType(Parent.class.getTypeParameters()[0]);
System.out.println(resolved); // "java.lang.Iterable<java.lang.String>"
final Class<?> raw = resolved.getRawType();
System.out.println(raw); // "interface java.lang.Iterable"
}
I don't think so. Read about type erasure: the generic types are used only for compile-time checking, and then discarded. They're not stored in the compiled class files so they're not available at runtime.