Say you have some class with type T:
class MyClass<T extends SomeOtherClass> {
....
}
Now, you want to store instances of this class into a collection, but you don't really care about the type. I would express this as following:
private final List<MyClass> entries = new ArrayList<>();
Is there any good reason/advantage to write the following instead?
private final List<MyClass<?>> entries = new ArrayList<>();
Or even:
private final List<MyClass<? extends SomeOtherClass> entries = new ArrayList<>();
I myself can only find a bad reason to do this: whenever the type definition of MyClass changes (for example addition of another type), you have to alter the List<MyClass<?>> or List<MyClass<? extends SomeOtherClass>> definitions all over your code as well.
update
To update my question:
Why isn't the compiler to be able to track the type(s) of MyClass when your write List<MyClass> (or even List<MyClass<? extends SomeOtherClass>>)? He knows that MyClass is defined as MyClass<T extends SomeOtherClass>, so why isn't he able/allowed to do that when you write List<MyClass>?
In other words, why is List<MyClass> not equal to List<MyClass<?>> (or even List<MyClass<? extends SomeOtherClass>>)? The compiler has all the information to make that conclusion himself, afaik.
The ? wildcard is useful when you don't need to refer to the type again and so you don't need to make a specific identifier.
Your first snippet starts with class MyClass<T extends SomeOtherClass>. This is necessary when T is important later on, perhaps to declare a field argument, or return type. For example:
class MyClass<T extends SomeOtherClass> {
private final List<T> aListOfT;
public T getSomething() {
return this.aListOfT.get(0);
}
Since MyClass is a generic type, all references to it should be qualified to avoid avoidable runtime errors. Thus when you declare List<MyClass> you get a compiler warning that you use the raw type MyClass. If you don't care at that location in the code what sort of type MyClass is qualified with, then you use the ? to tell the compiler that you don't care and let it track the type and check all operations for validity.
Your first declaration means, you are not giving any information about your generic data for the future reflection systems, could be used by plugins, which are written for your main program.
The second declaration tells them, that the field contains an Object generics.
The third one is the more specific, it means, that the reflection systems knows, what is this field about detailly.
Using the first type, java will assume that the generic type is Object. The reason for this is, that generics were introduced in version 1.5. Before then the collection-classes stored everything as an object. For compatibility reasons giving no generic parameter means that you are using object.
The second type simply says you don't know or don't care what type it is. This information is preserved when the code gets compiled. So other programmer who might use your code would know that you don't care.
Because of java's type-erasure, there is no difference between these two at runtime.
With the last form you say:
I don't care what it is, but it has to be SomeOtherClass or a derivated type. Which is the same as:
List<MyClass<SomeOtherClass>>
You can also do it the other way around:
List<MyClass<? super SomeOtherClass>>
says that you don't care what type it is, unless it is a supertype of SomeOtherClass.
Related
I know how to access generic types of fields using reflection: Just check if field.getGenericType() instanceof ParameterizedType.
But how can one check the same for an arbitrary object, not knowing where it was declared?
Generics apply to variable declarations, method return types, etc., not objects per-se. You can determine whether the Class of a particular object uses generics via myObj.getClass().getTypeParameters() but you can't determine what values of those type parameters the specific object instance was created with.
Objects do not store generic information per se, so the bytecode generated for new ArrayList<Integer>() is exactly the same as the one for new ArrayList<String>(). I mean exactly. This is what is called type erasure of Java generics. They are just desugared to new ArrayList().
But, in almost all other situations, type parameters are retained, like field/parameter/return type declarations. One of the cases that is retained and not erased is the super class of a class. So if you create a class that extends ArrayList<String> you can access that information at runtime.
But this seems overkill, doesn't it? A new class that extends ArrayList<String> and another one that extends ArrayList<String>, etc. seems impractical. Anonymous inner classes can make this much easier. So, if you want to keep the generic information, you just do new ArrayList<String>() {} instead of new ArrayList<String>(). You can call getClass().getGenericSuperclass() on the created object to get the generic info.
I have two classes, one abstract, one concrete:
abstract class Generator<T>;
class ConGenerator<T extends Complex<Z,Y>, Z extends Something1, Y extends Something2> extends Generator<T>;
Due to change in the number of parameters (I think), I cannot get the parameter classes at runtime using the usual approach with ParametrizedType, i.e.
ParameterizedType genericSuperclass = (ParameterizedType)getClass().getGenericSuperclass();
Type[] type = genericSuperclass.getActualTypeArguments();
All I am getting is the name I used for the param, T. I would appreciate any help in tackling this problem, I have already searched the web and used some libraries other people wrote for such problems; no luck so far.
The Problem
It is not always possible to infer type parameters given the runtime class, and yours is such a case. The root problem is that all instances of a generic class (irrespective of their type parameters) share the same runtime class, i.e.:
new ArrayList<Integer>().getClass() == new ArrayList<String>().getClass()
Therefore, it is impossible to discover the type parameters given just the runtime class, if that class is generic and different instances of that class can use different values for the type parameter. (Yes, we can find the type parameter for class X<T extends String>, because String is final, are therefore the only possible argument. Likewise, we can find the type parameters of List if we know the runtime class is class MappedList<T> implements List<String> { ... }).
In contrast, it is always possible to infer the type parameters of a super class if the runtime class is not generic - that's what all those libraries and code examples floating around the net do with various degrees of sophistication. For instance, if you have:
class StringArrayList extends ArrayList<String> { ... }
you can discover that the type argument to ArrayList is String. This also works with anonymous classes (as long as they are not generic), because:
new ArrayList<String>() {}.getClass() != new ArrayList<Integer>() {}.getClass()
but fails with generic classes such as
ArrayList<T> makeList(T t) {
return new ArrayList<T>(t) {};
}
because
makeList("2").getClass() == makeList(2).getClass()
The Solution
If you need the type at runtime, you will need to provide it by other means, typically by passing the Class object to the constructor. You can also use a super type token (an instance of a non-generic, usually anonymous, subclass of the desired type, which allows you to discover type parameters by reflection). This has the advantage that type parameters that are themselves generic can be expressed, too.
If you only need the class for a particular thing, there may be simpler alternatives. For instance, if you simply need to create new instances of the type parameter, a factory (method) pattern is quite a bit simpler :-)
I understand generics when it comes to collections. But what does it mean in the case of the Class<T> class? When you instantiate a Class object, there's only one object. So why the T parameter? What is it specifying? And why is it necessary (if it is)?
Type parameter <T> has been added to java.lang.Class to enable one specific idiom1 - use of Class objects as type-safe object factories. Essentially, the addition of <T> lets you instantiate classes in a type-safe manner, like this:
T instance = myClass.newInstance();
Type parameter <T> represents the class itself, enabling you to avoid unpleasant effects of type erasure by storing Class<T> in a generic class or passing it in as a parameter to a generic method. Note that T by itself would not be sufficient to complete this task2: the type of T is erased, so it becomes java.lang.Object under the hood.
Here is a classic example where <T> parameter of the class becomes important. In the example below, Java compiler is able to ensure type safety, letting you produce a typed collection from a SQL string and an instance of Class<T>. Note that the class is used as a factory, and that its type safety can be verified at compile time:
public static <T> Collection<T> select(Class<T> c, String sqlStatement) {
Collection<T> result = new ArrayList<T>();
/* run sql query using jdbc */
for ( /* iterate over jdbc results */ ) {
T item = c.newInstance();
/* use reflection and set all of item’s fields from sql results */
result.add(item);
}
return result;
}
Since Java erases the type parameter, making it a java.lang.Object or a class specified as the generic's upper bound, it is important to have access to the Class<T> object inside the select method. Since newInstance returns an object of type <T>, the compiler can perform type checking, eliminating a cast.
1 SUN Oracle has published a good article explaining all this.
2 This is different from implementations of generics without type erasure, such as one in .NET.
3 Java Generics tutorial by Oracle.
The answer by dasblinkenlight already demonstrated one of the main uses of this parameter. There is one more aspect I consider relevant: using that parameter, you can restrict the kind of class you want to pass at a given location. So e.g.
Class<? extends Number> cls
means that cls may be any class implementing the Number interface. This can help catching certain errors at compile time, and makes class argument requirements more explicit.
Perhaps a comparison to the case without generics is in order
// Java ≥5 with generics // Java <5 style without generics
Class<? extends Foo> c; Class c;
Foo t1 = c.newInstance(); Foo t1 = (Foo)c.newInstance();
Object obj; Object obj;
Foo t2 = c.cast(obj); Foo t2 = (Foo)c.cast(obj);
As you can see, not having T as an argument would require a number of explicit casts, as the corresponding methods would have to return Object instead of T. If Foo itself is a generic type argument, then all those casts would be unchecked, resulting in a sequence of compiler warnings. You can suppress them, but the core issue remains: the compiler cannot check the validity of these casts unless you properly use the type argument.
In Java there's a single metaclass: Class. Its instances (only one per type exists) are used to represent classes and interfaces, therefore the T in Class<T> refers to the type of the class or interface that the current instance of Class represents.
The use of generics in the Class type is top define the type of class. If I have ' Class obj' my object obj can holds only children of Charsequence.
This is an optional argument. I'm often put an '?' to avoid warnings from the Eclipse IDE if I don't need an specific type of 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.
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
which doesn't seem to add much value
but no longer gives a warning.
You're right. But this might add value:
Class<FooClass> fooClass;
or, if more appropriate:
Class<? extends FooClass> fooClass;
or
Class<FooInterface> fooClass;
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 makes Class 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 that fooClass of type Class<?> accepts a Class whose type matches anything.
Typical example:
Class<?> classUnknown = null;
classUnknown = ArrayList.class; //This compiles.
You can, effectively, provided a Parameterized Type to be more specific, e.g.:
Class<ArrayList> = ArrayList.class;
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).
The Javadoc of the Class class does give some idea about why type parameters exist for this class:
T - the type of the class modeled by
this Class object. For example, the
type of String.class is Class<String>.
Use Class<?> if the class being
modeled is unknown.
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:
public T newInstance()
throws InstantiationException, IllegalAccessException
{
if (System.getSecurityManager() != null) {
checkMemberAccess(Member.PUBLIC, ClassLoader.getCallerClassLoader());
}
return newInstance0();
}
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:
Class<String> fooClass;
Class<Integer> barClass;
String aString;
then, it is next to impossible to have the following code to compile:
aString = barClass.newInstance();
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.
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.
this morning I came across this code, and I have absolutely no idea what that means. Can anyone explain me what do these <T> represent? For example:
public class MyClass<T>
...
some bits of code then
private Something<T> so;
private OtherThing<T> to;
private Class<T> c;
Thank you
You have bumped into "generics". They are explained very nicely in this guide.
In short, they allow you to specify what type that a storage-class, such as a List or Set contains. If you write Set<String>, you have stated that this set must only contain Strings, and will get a compilation error if you try to put something else in there:
Set<String> stringSet = new HashSet<String>();
stringSet.add("hello"); //ok.
stringSet.add(3);
^^^^^^^^^^^ //does not compile
Furthermore, another useful example of what generics can do is that they allow you to more closely specify an abstract class:
public abstract class AbstClass<T extends Variable> {
In this way, the extending classes does not have to extend Variable, but they need to extend a class that extends Variable.
Accordingly, a method that handles an AbstClass can be defined like this:
public void doThing(AbstClass<?> abstExtension) {
where ? is a wildcard that means "all classes that extend AbstClass with some Variable".
What you see here is something called Generics. They were introduced to Java in release 1.5.
You can read about them here and here. Hope this helps.
Imagine you're writing a List or Array class. This class must be able to hold elements of an unknown type. How do you do that?
Generics answers this question. Those <T> you're seeing can be read as some type. With generics you can write class MyList<T> { ... }, which in this context means a list that holds some type.
As an usage example, declare a list to store integers, MyList<Integer> listOfInts, or strings, MyList<String> listOfStrings, or one class you've written yourself MyList<MyClass> listOfMyClass.
What you are seeing is Java generics, which allows classes and methods to be parameterized by other classes. This is especially useful when creating container classes, since it saves you having to create separate classes for "a list of integers", "a list of strings", etc. Instead, you can have a single "list of some type T, where T is a variable" and then you can instantiate the list for some specific type T. Note that Java generics is not quite the same as template types in C++; Java generics actually use the same class definition but add implicit casting (generated by the compiler) and add additional type-checking. However, the different instantiations actually make use of the same exact type (this is known as erasure), where the parameterized types are replaced with Object. You can read more about this at the link.
Since noone has mentioned it yet, there is a very comprehensive guide/FAQ/tutorial on generics which can be found on Angelika Langer's site.