Reputation: 53
I need to initialize a variable of type Class<Set<String>>
When I use Set.class it returns variable of Class<Set>
Class<Set> clazz = Set.class;
When I try
Class<Set<String>> clazz = Set<String>.class;
I have a compile error.
Upvotes: 4
Views: 723
Reputation: 122449
First, you need to understand that, at runtime, there is only one Class
object representing the Set
interface. There are no separate Class
objects for Set<String>
, Set<Integer>
, etc. So the most that your variable of type Class<Set<String>>
can do at runtime is point to this one Set
class object, and the question is does it make sense for it to do so?
Let's consider what you can do with a variable of type Class<Set<String>>
.
.cast()
method. Normally, if you have a Class<T> clazz
, clazz.cast(x)
returns type T
, and what it does at runtime is it checks that the passed object is an instance of the class, and if not, it throws an exception; that's why it's safe for it to return the type T
. However, if your variable points to the Class
object that represents the Set
interface, then its .cast()
can only check that the object is an instance of Set
, not that it is an instance of Set<String>
(which is not possible anyway, since objects do not know their generic type arguments at runtime; if you did a cast (Set<String>)x
, it would give an unchecked cast warning; so it would not make sense if you were able to "bypass" the warning by doing Set<String>.class.cast(x)
without a warning), so it cannot "safely" return type Set<String>
..isInstance()
method. Normally, if you have a Class<T> clazz
, clazz.isInstance(x)
returns true or false depending on whether the passed object is an instance of T
. But just with .cast()
, it is not possible to check the generic type argument of an object at runtime, so calling a Class<Set<String>>
's .isInstance()
method might not give the "correct" answer..newInstance()
method or by getting a constructor and using the constructor's .newInstance()
method. Well, in this case, Set
is an interface and cannot be instantiated; let's instead consider say, HashSet
. With a Class<HashSet<String>>
, you can call .newInstance()
to get a HashSet<String>
using the no-parameter constructor. In this case, it is safe, because there is no difference between new HashSet()
and new HashSet<String>()
and new HashSet<Integer>()
at runtime. However, if you get a constructor with parameters, it may be potentially unsafe if the type T
is used in the parameters, because there is no way for it to check that the passed arguments match those types (since it doesn't know T
at runtime).So as you can see, a Class<Set<String>>
cannot safely fulfill the contract of the Class
class for some of its functionality. Therefore, you should not be able to get a Class<Set<String>>
without warnings. If you are sure that it is safe for your use case to consider the Class
object representing Set
as a Class<Set<String>>
, then you can manually force it by doing (Class<Set<?>>)(Class<?>)Set.class
, but you will get a warning which means you take responsibility for making sure it's safe.
Upvotes: 3