Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why is using Collection<String>.class illegal?

Tags:

java

I am puzzled by generics. You can declare a field like:

Class<Collection<String>> clazz = ... 

It seems logical that you could assign this field with:

Class<Collection<String>> clazz = Collection<String>.class; 

However, this generates an error:

Syntax error on token ">", void expected after this token

So it looks like the .class operator does not work with generics. So I tried:

  class A<S> { }   class B extends A<String> { }   Class<A<String>> c = B.class; 

Also does not work, generates:

Type mismatch: cannot convert from Class<Test.StringCollection> to Class<Collection<String>>

Now, I really fail to see why this should not work. I know generic types are not reified, but in both cases it seems to be fully type safe without having access to runtime generic types. Anybody an idea?

like image 286
Peter Kriens Avatar asked Apr 30 '10 14:04

Peter Kriens


People also ask

What is use of collections class in Java?

public class Collections extends Object. This class consists exclusively of static methods that operate on or return collections. It contains polymorphic algorithms that operate on collections, "wrappers", which return a new collection backed by a specified collection, and a few other odds and ends.

What is collection API in Java?

The Collections API also provides reusable functionality with a core set of algorithms that operate on List collections. Furthermore, the polymorphic nature of these algorithms enables their operation on a variety of classes that implement a common interface.

What does .class mean in Java?

What Does Class Mean? A class — in the context of Java — is a template used to create objects and to define object data types and methods. Classes are categories, and objects are items within each category. All class objects should have the basic class properties.

What is the class of list string in Java?

Answer: The list is an interface in Java that extends from the Collection interface. The classes ArrayList, LinkedList, Stack, and Vector implement the list interface.


2 Answers

Generics are invariant.

Object o = "someString"; // FINE! Class<Object> klazz = String.class; // DOESN'T COMPILE! // cannot convert from Class<String> to Class<Object> 

Depending on what it is that you need, you may be able to use wildcards.

Class<? extends Number> klazz = Integer.class; // FINE! 

Or perhaps you need something like this:

Class<List<String>> klazz =    (Class<List<String>>) new ArrayList<String>().getClass(); // WARNING! Type safety: Unchecked cast from //   Class<capture#1-of ? extends ArrayList> to Class<List<String>> 

As for the non-reified at run-time case, you seem to have a good grasp, but here's a quote anyway, from the Java Tutorials on Generics, The Fine Print: A Generic Class is Shared by All Its Invocations:

What does the following code fragment print?

List <String> l1 = new ArrayList<String>(); List<Integer> l2 = new ArrayList<Integer>(); System.out.println(l1.getClass() == l2.getClass()); 

You might be tempted to say false, but you'd be wrong. It prints true, because all instances of a generic class have the same run-time class, regardless of their actual type parameters.

That is, there's no such thing as List<String>.class or List<Integer>.class; there's only List.class.

This is also reflected in the JLS 15.8.2 Class Literals

A class literal is an expression consisting of the name of a class, interface, array, or primitive type, or the pseudo-type void, followed by a . and the token class.

Note the omission of any allowance for generic type parameters/arguments. Furthermore,

It is a compile time error if any of the following occur:

  • The named type is a type variable or a parameterized type, or an array whose element type is a type variable or parameterized type.

That is, this also doesn't compile:

void <T> test() {     Class<?> klazz = T.class; // DOESN'T COMPILE!     // Illegal class literal for the type parameter T } 

Basically you can't use generics with class literals, because it just doesn't make sense: they're non-reified.

like image 144
polygenelubricants Avatar answered Sep 28 '22 19:09

polygenelubricants


I agree with the other answers, and would like to explain one point further:

Class objects represent classes that are loaded into the JVM memory. Each class object is actually an in-memory instance of a .class file. Java generics are not separate classes. They are just a part of the compile-time type-checking mechanism. Therefore, they have no run-time representation in a class object.

like image 43
Little Bobby Tables Avatar answered Sep 28 '22 17:09

Little Bobby Tables