Java generics (type erasure) - java

Is it possible to something like:
Widget w = Gadet<Widget>().getInstance();
(Edit: getInstance invocation returns a newly created instance of the specified generic type parameter)
I do know about java's type erasure (atleast to some extent). But I got a little bit confused when i ran across
this.instanceClass = (Class<T>) ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0];
on hibernate.org

You want to pass in ANY class, and get an instance of that type -- statically, i.e. without reflection? Nope, that's not possible -- due to type erasure, right.
The only way to pass in ANY class is to pass it as a parameter:
Object getInstance(Class clz){ ... };
Even if you define it as
Object getInstance(Class<T> clz){ ... };
T is lost at runtime. All you have is class. I suppose language designers could make it sweeter by allowing things like:
new T()
which under the hood would do clz.newInstance(), but they didn't.

Hm ... to fully answer your question, a little background is required:
Erasure means that actual type parameters are not included in bytecode, and hence the dynamic type of a type parameter is unknown at runtime, making it generally impossible to instanciate it. (Which is why new T() for a type parameter T does not compile.)
However, actual type parameters specified in declarations of fields, methods or classes are recorded in the class file, and available to reflection. Under certain circumstances, the latter information is sufficient to determine to value of the type parameter.
For instance, the snippet from the hibernate website, if declared in class C<T>, infers the actual type of T if getClass() is a direct and non-generic subclass of C, by reflecting on the extends clause of that class' declaration. (If that extends clause however contained another type variable as in class D<T> extends C<T>, the method would throw a ClassCastException when attempting to cast a type variable to Class<?>).
If is possible to generalize that snippet to work for any non-generic getClass() (direct or otherwise), but if getClass() is generic the limited information the runtime retains about type parameters is insufficient to determine the type.

You could do something like the following:
public static <T> T getInstance(Class<T> klass) {
try {
return klass.newInstance();
} catch (Exception ex) {
//Do some real error handling here probably
return null;
}
}

Related

How to get the original type (instead of E) for a Parameterized type with generics using reflection? [duplicate]

I have read Get type of a generic parameter in Java with reflection post and it made me wonder how that would be possible. I used the solution that someone posted and using the code
List<Integer> l = new ArrayList<>();
Class actualTypeArguments = (Class) ((ParameterizedType) l.getClass().getGenericSuperclass()).getActualTypeArguments()[0];
This, however does not work for me, resulting in
java.lang.ClassCastException: sun.reflect.generics.reflectiveObjects.TypeVariableImpl cannot be cast to java.lang.Class
If I remove the class cast, the type of the actual argument is E, which is the type definition from List interface.
My question is, therefore, am I doing something wrong here? This behaviour is something I would have expected anyway, since the types are supposed to be erased during compile time, correct?
The code you use only works in some very specific cases, where the actual type parameter is known (and stored) at compile time.
For example if you did this:
class IntegerList extends ArrayList<Integer> {}
List<Integer> l = new IntegerList();
In this case the code you showed would actually return Integer.class, because Integer is "baked into" the IntegerList.
Some libraries (ab)use this trick via the use of type tokens. See for example the GSON class TypeToken:
Represents a generic type T. You can use this class to get the generic type for a class. > For example, to get the generic type for Collection<Foo>, you can use:
Type typeOfCollectionOfFoo = new TypeToken<Collection<Foo>>(){}.getType()
This works because the anonymous class created in here has compiled-in the information that its type parameter is Collection<Foo>.
Note that this would not work (even if the TypeToken class wouldn't prevent it by making its constructor protected):
Type typeOfCollectionOfFoo = new TypeToken<Collection<Foo>>().getType()
The javadoc will tell you what you are doing.
Class#getGenericSuperclass() states
Returns the Type representing the direct superclass of the entity
(class, interface, primitive type or void) represented by this Class.
If the superclass is a parameterized type, the Type object returned
must accurately reflect the actual type parameters used in the source
code. [...]
The direct superclass of ArrayList is AbstractList. The declaration is as such in the source code
public class ArrayList<E> extends AbstractList<E>
implements List<E>, RandomAccess, Cloneable, java.io.Serializable
So if you print out the Type object returned by it, you will see
java.util.AbstractList<E>
and therefore ParameterizedType#getActualTypeArguments() which states
Returns an array of Type objects representing the actual type
arguments to this type.
will return the Type
E
since E is the actual type argument used in the ArrayList class definition.
The method you described does ONLY work, when the Generic Type is Set due to inheritance, because then its known during compile time:
public class SomeClass<T>{
}
public class SpecificClass extends SomeClass<String>{
}
For this example, you can use the method and you'll get back "String.class".
If you are creating instances on the fly it won't work:
SomeClass s = new SomeClass<String>(); //wont work here.
Some common work around is, to pass the actual class as a parameter for later reference:
public class SomeClass<T>{
Class<T> clazz
public SomeClass(Class<T> clazz){
this.clazz = clazz;
}
public Clazz<T> getGenericClass(){
return this.clazz;
}
}
usage:
SomeClass<String> someClass= new SomeClass<String>(String.class);
System.out.println(someClass.getGenericClass()) //String.class
Actually you don't even need the Generic type for such an scenario, because Java would do the same thing, as if you would handle the "T" as Object. Only advantage is, that you can define getter and Setter of T and don't need to typecast Objects all the time. (Because Java is doing that for you)
(It's called Type Erasure)

What is the benefit of using Class<?> instead of Class as a method parameter type?

NB: This is not a duplicate of the question I have already linked to below. I obviously read that question/answer first before posting and did not have my question answered in any form.
This linked question does go into more detail explaining why the generic Class exists. However I don't get an answer specifically to the benefits of Class in my situation.
What does the generic nature of the class Class<T> mean? What is T?
I've written a utility method that accepts a parameter 'cl' of type Class and performs logic by using cl.isInstance(objectInstance) method.
However I've seen example code that declares parameters using the generic wildcard Class<?>.
Why not just use Class without the generic wildcard? Can't Class represent all possible class types including generics? What is the benefit, if any of using Class<?> in my situation?
The accepted answer in an existing related question (see below) does not actually provide a useful answer.
What does Class<?> mean in Java?
The main difference lies in the (self-)documentation of the code to the reader. A variable declared as Class<?> says: “the actual type represented by this Class instance is unknown or not representable at compile-time and I know that”. In contrast the type Class says: “I’m not using Generics here”, perhaps, because you don’t know that Class is generic, or you are a bit sloppy, didn’t understand the difference between Class<?> and Class, or this is very old pre-Generics code.
This has consequences for the code. E.g.
Class<?> unknownType=Object.class;
Class<String> string=unknownType;
produces a compile-time error as you are assigning an explicitly unknown type to a variable declaring a known type.
In contrast
Class nonGenericType=Object.class;
Class<String> string=nonGenericType;
will only produce a (suppressible) warning as you are performing a non-generic, aka unchecked, operation.
Regarding what you can do with a Class object, besides assignments, there is no difference, as, when you use it to create a new instance, the compile-time type of the returned reference will be the most abstract type there is, java.lang.Object, in both cases. Had Class methods receiving arguments related to the type parameter, a difference showed up as you can’t invoke such methods for an unknown type, Class<?> (it would be the same as trying to insert an element into a List<?>) while you could invoke such a method unchecked on a raw Class instance. But since there are no such methods, there’s no difference in functionality between Class<?> and Class.
Still, you should always use Class<?> to be sure that no accidental unchecked operations, like the assignment shown above, happen. If using Class doesn’t produce compiler warnings, you should check how to (re-)enable them. If the compiler silently ignores raw types or unchecked operations, there might be other problems, with other types than Class, hiding somewhere.
The difference between the wildcard type <?> and the raw type in this particular scenario is only whether the compiler will warn you or not. Otherwise they're equivalent, so if for some reason you don't wouldn't want to use the <?> syntax and you didn't care about compiler warnings, you could use the raw type without any problems.
Netbeans not complaining about the raw type is not correct behaviour, and my Eclipse will complain when using a raw Class.
The Class object has distinct usage patterns, which affect whether the type will be a concrete type (seen in method parameters as Class<T> clazz) or the wildcard Class<?>.
The most common form seen in the API is the concrete type, since it allows you to use newInstance() (primarily) in a type-safe way (making all Class<T> objects automatically type-safe factories), such as the following:
public static void List<T> fill(Class<T> clazz, int size) {
List<T> l = new ArrayList<T>();
for(int i = 0;i < size; i++)
l.add(clazz.newInstance());
return l;
}
So Class<T> is useful, but what about Class<?>? Well, not so much. As indicated at the beginning, it's just required for syntax compliance. The alternative would be to use a concrete T type redundantly.
public void foo(Class<?> clazz) {
// Do something non-typed, we don't have a type
}
vs.
public <T> void foo(Class<T> clazz) {
// Do something non-typed, even though we have a type T
}

Generic Type Erasure Warning

I have this code from the book Thinking in Java,where Bruce indicates the warning on calling the method set(). The code is as follows:
package testPackage;
class GenericBase<T> {
private T element;
public void set(T arg) { arg = element; }
public T get() { return element; }
}
class Derived1<T> extends GenericBase<T> {}
class Derived2 extends GenericBase {} // No warning
// class Derived3 extends GenericBase<?> {}
// Strange error:
// unexpected type found : ?
// required: class or interface without bounds
public class ErasureAndInheritance {
#SuppressWarnings("unchecked")
public static void main(String[] args) {
Derived2 d2 = new Derived2();
Object obj = d2.get();
d2.set(obj); // Warning here!
}
}
If I remove the annotation, I get the following warning:
Type safety: The method set(Object) belongs to the raw type GenericBase. References to generic type GenericBase should be parameterized
My question is, Why is the warning displayed on the set() method? And can somebody please explain what this warning means?
Btw, I am completely new to Java Generics and although I read other questions on Generics, I am still somewhat confused on Erasure.
From the Java doc here
Generics were introduced to the Java language to provide tighter type
checks at compile time and to support generic programming. To
implement generics, the Java compiler applies type erasure to:
Replace all type parameters in generic types with their bounds or Object if the type parameters are unbounded. The produced bytecode,
therefore, contains only ordinary classes, interfaces, and methods.
Insert type casts if necessary to preserve type safety.
Generate bridge methods to preserve polymorphism in extended generic types.
Type erasure ensures that no new classes are created for parameterized types; consequently, generics incur no runtime overhead.
Simple: Every generic is a Object after the compile process, it just adds the casting for you, and if you did something wrong it will generate a compiler error.
About the unchecked annotation, it's used when the compiler can't be sure that what are you doing is correct (in fact, you use the raw type which is the same thing as GenericBase<Object>)
You have the warning since the set methods except the type T but since you are using a raw type, it don't know what T is, and generate this warning to let you know that you are using a raw type (bad thing).
You can use the annotations to say: "I know it's a raw type, but i know it's legal and i know what i'm doing".
Mixing raw types and generic types is possible due to the way that generics are implemented, as i said above, after the compiler process the T becomes Object and it means that a raw object like GenericBase is the same thing like GenericBase<T>.
The reason that it doesn't asks for any casting with generics, is because it will add the casts for you (and you can be sure that the code will always work in runtime without worry about a possible ClassCastException).

When is it acceptable to pass a Class<T> argument to a generic method?

Methods that are generic using the T parameter can for sure be handy. However, I am curious what the use of a generic method would be if you pass an argument such as Class<T> clazz to the method. I've come up with a case that maybe could be an possible use. Perhaps you only want to run a part of the method based on the type of class. For example:
/** load(File, Collection<T>, Class<T>)
* Creates an object T from an xml. It also prints the contents of the collection if T is a House object.
* #return T
* Throws Exception
*/
private static <T> T void load(File xml, Collection<T> t, Class<T> clazz) throws Exception{
T type = (T) Jaxb.unmarshalFile(xml.getAbsolutePath(), clazz); // This method accepts a class argument. Is there an alternative to passing the class here without "clazz"? How can I put "T" in replace of "clazz" here?
if (clazz == House.class) {
System.out.println(t.toString());
} else {
t.clear();
}
return T;
}
Is this an accepted practice? When is the Class<T> clazz argument useful with generic methods?
Is this an accepted practice?
Well, to me.. no not really. To me, it seems somewhat pointless when you can simply define some boundaries on the type of T. For example:
private static <T extends House> void load(Collection<T> t)
This will guarantee that either the object is of type House or of a subclass of House, but then again if you only want an instance of type House or it's subclasses, it should really just be:
private static void load(Collection<House> houses)
The idea of generics is to make a method or a class more malleable and extensible, so to me it seems counter-intuitive to start comparing class types in the method body, when the very notion of generics is to abstract away from such details.
I'd only pass class objects if the generic type could not be derived otherwise. In your case, the compiler should be able to infer T from the collection. To treat specific objects differently, I'd use polymorphism - e.g. House#something() and Other#something(), and just call anyObject.something().
I think it is acceptable but if it can be avoided then you should. Typically, if you can have different methods which accepts different type, then do it instead of one method which uses if clauses to do something different depending on the type of the parameter. You could also delegates to the class the operation you want to make specific for a given type.
In your case, you could simply test the type of each element of the collection using instanceof, to do what you need for the specific type. But it won't work if the list is empty.
A typical use is if you need to get the type to create it and you can find it from another way. For instance, Spring uses it to load a bean from its name:
<T> T getBean(Class<T> requiredType)
In that case, it cannot be avoided (without having to cast).
If the returned value or other parameters types are dependent or need to be equal, generics will add compile time checks, so that there's no need to cast to T.
Examples
<T> T createNewInstanceOfType(Class<T> type);
<T> void addValueToCollection(Collection<T> collection,T value);
<T> List<Class<? extends T>> findSubClassesInClasspath(Class<T> superType);
Raw types
It is still possible to defer a casting error until runtime (ClassCastException) with some casts, e.g. with implicit casts from non-generic (raw) types to generic ones:
List nonGenericList = new ArrayList();
nonGenericList.add(new Integer(42));
List<String> wreckedList = nonGenericList;
The compiler will generate a bunch of warnings, unless you suppress them with annotations or compiler settings.
Compiler Settings (Eclipse):
For example, the usage of raw types generates a warning per default, one can treat warnings as errors and even as fatal errors:
You would pass a Class<T> argument in generics if, and only if, you would pass a Class argument before generics. In other words, only if the Class object is used in some way. Generics serves as a compile-time type checking tool. However, what arguments you pass should be determined by the runtime logic of the program, and should be irrelevant of generics.
I haven't seen passing a Class object in order to check the runtime type of an object as a common use case for generics. If you're doing that, there's a good chance that there's a better way to set up your class structure.
What I have seen is if you need to create a new instance of the class in question, or otherwise use reflection. In that case you do have to pass the Class object, because Java cannot derive it at runtime thanks to type erasure.
In your case actually having the Generic parameter is not strictly needed.
Since the output of the function you are describing does not depend on the type of the input you might as well use wild cards.
private static void stuff(Collection<?> t){
Object next = t.iterator().next(); //this is ugly and inefficient though
if(next instanceof House){
System.out.print(next.toString());
}else{
t.clear();
}
}
The only time you should use generic parameter is when the type of the result of a function will be dependent of the type of the parameters.
You will need to pass the Class corresponding to the type when your code will need it; most of the time this happens when:
- You need to cast/type check objects to T
- There is serialization/deserialization involved.
- You cannot access any instance of T in your function and you cannot call the getClass() method when you need it.
Passing a Class on every generic function will result in you passing an unnecessary parameter most of the time, which is regarded as bad practice.
I answered a similar discussion in the past:
When to use generic methods and when to use wild-card?

Java: getting inner type in nested parameterized types (reflection)

Most of the documentation regarding type erasure handling in Java assumes that the use case is handling a type like SomeType<ParamType>.
I am trying to process method parameter for the following method:
public void setOtherReferenceRanges(List<ReferenceRange<T>> referenceRanges)
When the container class is instantiated with a type DvQuantity, this signature should become
public void setOtherReferenceRanges(List<ReferenceRange<DvQuanitity>> referenceRanges) in runtime.
Using reflection one can see that the List has an actualTypeArgument which is ReferenceRange<T>. Since reflection uses class information, I would not expect it to give me ReferenceRange<DvQuantity>.
However, when I created the class containing this method, I passed the DvQuantity type as T. So the type filling in T should be available to Java runtime, but I could not find a way of getting it. I end up with a TypeVariableImpl object accessed via reflection, which does not seem to contain any useful data.
Can you think of any ways to discover this information in runtime?
When you say
when I created the class containing this method
I guess you mean when you create an object of that type, for example:
foo = new ContainerClass<DvQuantity>();
In that case, because of erasure, there is no way to recover the type DvQuantity.
However, if you create a class passing a type parameter to the superclass, like this
class DvQuantityContainerClass extends ContainerClass<DvQuantity> {...}
...
foo = new DvQuantityContainerClass();
Or, shorter, an inline anonymous subclass (which looks almost like the first example but with a subtle but important difference):
foo = new ContainerClass<DvQuantity>(){};
Then you can recover the type parameter, because you recover the type parameter used to extend a superclass at runtime. Unfortunately, Java itself doesn't provide an easy way to now get the type of the DvQuantityContainerClass.setOtherReferenceRanges method with the T filled in. For that, I've written gentyref, to do advanced reflection on generic types:
Method m = DvQuantityContainerClass.class.getMethod("setOtherReferenceRanges", List.class);
// this will return List<ReferenceRange<DvQuanity>>, like you are lookingn for
return GenericTypeReflector.getExactParameterTypes(m, DvQuantityContainerClass.class)
Generic type information is erased by the compiler and is not available at runtime. When I need to ensure a certain type at runtime I pass in a class argument:
public <T> void doSomething(T t, Class<T> c);
This is not always convenient or even possible, but for many cases it is possible.
So the type filling in T should be available to Java runtime, but I could not find a way of getting it.
Perhaps it's not entirely correct, but the way I think about it is that at runtime there is no actual class - just an object without a specific type which meets the interface of T. In other words, erasure happens not with objects, but instead with these nebulous (in the OOP world at least) type-things.
http://java.sun.com/docs/books/tutorial/java/generics/erasure.html
There are ways of capturing the type information inside the class itself (T types would need a method getUnderlyingType()... or something), but that's a bad idea. If you truly need to raw type of the object, I'd reconsider using generics.

Categories

Resources