Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why is Class<?> preferred to Class

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.

like image 808
peter.murray.rust Avatar asked Dec 02 '10 16:12

peter.murray.rust


People also ask

What is class <?> Mean in Java?

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.

Why do we use T in generics?

In other words, the T is an actual part of the syntax for Generics and it means that the paramter for the Class can be of variable type? <T> is the generic type. Maybe read the official tutorial. Yes, the angle-brackets with one (or more) types is the syntax for generics.

What is a parameterized class?

A parameterized class is a generic or skeleton class, which has formal parameters that will be replaced by one or more class-names or interface-names. When it is expanded by substituting specific class-names or interface-names as actual parameters, a class is created that functions as a non-parameterized class.

What is parameterized class in Java?

The type parameter section of a generic class can have one or more type parameters separated by commas. These classes are known as parameterized classes or parameterized types because they accept one or more parameters.


1 Answers

Raw Types and Unbounded Wildcards

None of the previous answers have really addressed why you should prefer Class<?> over Class, 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:

public void foo(Class<String> c) { System.out.println(c); } 

Can be called thusly (it will both compile and run):

Class r = Integer.class foo(r); //THIS IS OK (BUT SHOULDN'T BE) 

But not by:

Class<?> w = Integer.class foo(w); //WILL NOT COMPILE (RIGHTLY SO!) 

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:

The use of raw types is allowed only as a concession to compatibility of legacy code

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:

public interface FooService 

And I want to inject an implementation of it, using a system property to define the class to be used.

Class<?> c = Class.forName(System.getProperty("foo.service")); 

I do not know at this point that my class, is of the correct type:

//next line throws ClassCastException if c is not of a compatible type Class<? extends FooService> f = c.asSubclass(FooService.class);  

Now I can instantiate a FooService:

FooService s = f.newInstance(); //no cast 
like image 68
oxbow_lakes Avatar answered Oct 19 '22 17:10

oxbow_lakes