If I declare a Class as a field:
Class fooClass;
Eclipse gives me the warning:
Class is a raw type. References to generic type Class should be parametrized
What does this mean in practice? and why am I urged to do it? If I ask Eclipse for a "quick fix" it gives me:
Class<?> fooClass;
which doesn't seem to add much value but no longer gives a warning.
EDIT: Why is Class generic? Could you please give an example of parameterization, i.e. could there be a valid use of something other than <?>
?
EDIT: WOW! I had not realized the depths of this. I have also watched the Java Puzzler and it's certainly scared me about the bear traps. So I will always use
Class<MyString> myStringClass = MyString.class;
rather than
Class myStringClass = MyString.class;
(But having used Java from day one, I didn't really notice when Class became generic);
NOTE: I have accepted @oxbow_lakes as this makes sense to me, but it is clearly a very complicated area. I would urge all programmers to use the specific Class<MyString>
rather than Class
. And Class<?>
is much safer than Class
.
Raw Types and Unbounded Wildcards
None of the previous answers have really addressed why you should prefer
Class<?>
overClass
, as on the face of it, the former seems to offer no more information than the latter.The reason is that, the raw type, i.e.
Class
, prevents the compiler from making generic type checks. That is, if you use raw types, you subvert the type-system. For example:Can be called thusly (it will both compile and run):
But not by:
By always using the non-raw form, even when you must use
?
because you cannot know what the type parameter is (or is bounded by), you allow the compiler to reason about the correctness of your program more fully than if you used raw types.Why have Raw Types at all?
The Java Language Specification says:
You should always avoid them. The unbounded wildcard
?
is probably best described elsewhere but essentially means "this is parameterized on some type, but I do not know (or care) what it is". This is not the same as raw types, which are an abomination and do not exist in other languages with generics, like Scala.Why is Class Parameterized?
Well, here is a use-case. Suppose I have some service interface:
And I want to inject an implementation of it, using a system property to define the class to be used.
I do not know at this point that my class, is of the correct type:
Now I can instantiate a
FooService
:You're right. But this might add value:
or, if more appropriate:
or
As with generics in general, you can improve type safety by specifying what kind of class you want the variable to hold. The warning against raw types is just meant to catch pieces of code where this potential is not used. By declaring
Class<?>
you're basically saying "this is meant to hold any kind of class".Because, since JDK 5,
Class
has now have parameterized type, which makesClass
a generic object. This is necessary (since the introduction of Generics) for the compiler to do type checking (at compile time, of course).Class<?>
means a "class of unknown" where?
is a generics wildcard. It means a thatfooClass
of typeClass<?>
accepts aClass
whose type matches anything.Typical example:
You can, effectively, provided a Parameterized Type to be more specific, e.g.:
PS Bear in mind, that
Class<List> listClass = ArrayList.class;
won't compile (even though ArrayList is of List) but (as Mark Peters mentioned on the comment)Class<? extends List> listClass = ArrayList.class;
does compile (thanks to the wildcard).Because using raw types instead of parameterized types has many pitfalls.
One of which is that if a raw type is used, all generics on the class are lost. Even those defined per-method.
The Javadoc of the Class class does give some idea about why type parameters exist for this class:
The use of this type parameter is not so obvious, but a cursory look at the source code of the class, indicates why the type parameter is sometimes necessary. Consider the implementation of the
newInstance
method:If one hasn't noticed, the type of the object returned by this method is that of the type parameter. This is useful in code that utilizes a lot of reflection, and where one would like to be extra careful to ensure that objects of the right type are being instantiated.
Considering the example in the question, if the class instance was instead declared as:
then, it is next to impossible to have the following code to compile:
In short, if you're going to be working with class hierarchies and you wish to impose strict compile time checks to ensure that your code does not need to perform a lot of
instanceof
checks, then you're better off specifying the type of the class that you wish to utilize. Specifying?
allows all types, but there would be cases when you'll need to be more specific.