How can I access Class object for Generics?
Currently, I am doing it this way:
List<String> list= new ArrayList<String>();
list.getClass();
Is this OK? Or, what should be the way?
That will return the same as ArrayList.class. Java generics erase the generic type at runtime; in other words, from "list" you'll never know the element type is String. There's a great FAQ on this at
http://www.angelikalanger.com/GenericsFAQ/JavaGenericsFAQ.html
It is true that erasure makes it impossible to get the generic type info of a given object, since the generics is only held in the structure of the source code. However, this does not mean it's impossible to get generic type parameters and in many important cases (e.g. building interfaces to a given class/method) you are able to do this. If you get hold of a class' elements via reflection, you can get generic information about the declared types used.
For example, get hold of a java.lang.reflect.Method via reflection, and call e.g. getGenericReturnType() on it. This will return an instance of java.lang.reflect.Type, which can be simply a Class but could also be an instance of ParameterizedType or even WildcardType where appropriate. Both of these latter cases allow you to see the declared generic types. I am not aware of any particularly elegant way to handle this other than instanceof checks, but the information is there if you need it.
This can give information on the generics types of fields, of method parameters and return types, and of the class itself (both its own generic parameters and those of its superclass and implemented interfaces). This can be very useful if you need to do type-safe argument checking for generic methods in a reflective context.
Related
Let's suppose you're writing a library, and it is to act upon a client class that is passed to it (i.e. client code cannot be changed).
class ClientClass {
public GenericClientClass<AnotherClientClass> someField;
}
What I'm trying to do is instantiate someField through reflection. Something like:
class LibraryClass{
public instantiateAllFields(Object obj){
//iterate through all fields of obj.class, and instantiate them
}
}
The only requirement of the client's fields is that a constructor without arguments exists. (e.g. GenericClientClass() {} )
The purpose of this is to create a highly automated testing library, currently for my own purposes.
I've been able to implement the above for almost all cases (arrays, objects, primitives, generic arrays etc.); however, this particular case has stumped me.
field.getType().newInstance() does not work, since the generic type parameters are removed.
field.getGenericType() doesn't work, because it returns a type, not a class.
If It's a known generic class, I can create a special case to deal with it. For example:
Class<?> genClass = ((Class<?>)((ParameterizedType)field.getGenericType()).getActualTypeArguments()[0]);
JArray jArray = new JArray(true,n,genClass);
field.set(object, jArray);
...I'm guessing I could do this for things like ArrayList, HashMap etc.
However, I would like to cover the general case, and be able to instantiate any generic class (with a single parameter, and a zero-argument constructor) that may be passed into the library.
Any ideas?
Note that the type of the generic parameter is known. I can get at it through field.getGenericType().
There's no such thing as "an instance of a parameterized type"; or, rather, there's no difference between instances of parameterized types with different type parameters. The type parameter is just something the compiler uses to enforce type correctness.
If you're instantiating it at runtime, the compiler is not in the loop. So you just have to create a "raw"/"wildcard"-typed instance, and cast it; and you have to own the problem of ensuring that the cast actually is safe.
Assuming GenericClientClass is not abstract, and has a constructor without parameters:
someField = (GenericClientClass<AnotherClientClass>) GenericClientClass.class.getConstructor().newInstance();
and deal with the resulting unchecked cast warning appropriately.
How can you determine what type of object a generic is using at runtime ?
Due to type erasure, you cannot determine the actual type parameter(s) of a generic object instance. The best you can do is set things up so you can pass a class object to code that needs to know the actual type. For example, this is what java.util.EnumMap does in one of its constructor.
If you mean the T in List<T> (for instance), you can't, because Java uses type erasure. At runtime, a List<T> just looks like a List. This is true except in the edge case of anonymous classes, where it's possible if you jump through hoops to find the parameter type. But in the general case, you cannot. You usually have to communicate that information separately.
First we explain What is Generic
Generic in Java is one of important feature added in Java 5,
From Oracle's documentation:
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.
Now how to make possible to get the generic type on runtime, with the help of this link
read: http://www.west-wind.com/weblog/posts/2011/Nov/11/Dynamically-creating-a-Generic-Type-at-Runtime
It is not possible to get the object type of "Generics" at run time. If we use object.getclass(), so we can get object of any class with the class name.
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 seen it mentioned on some places online that in some situations it is possible to use the reflection API to get back information about generic data types which I thought would be lost through type erasure.
I am looking for complete list of the situations where type erasure is not complete i.e. something is still accessible via reflection. A Good list of examples and associated reflection code that can get at the generic types would be excellent.
UPDATE http://tutorials.jenkov.com/java-reflection/generics.html had exactly the examples I was looking for.
I think it just comes down to this:
No object instance stores any type information.
The classes, however, retain all their generic signatures (otherwise you could not have any generic type checking at compile time)
So, using reflection, you can read the generic type information for a given class.
Example:
class MyList extends ArrayList<MyObject>{}
List<MyObject> x = new MyList();
Reflection will tell you that this is a List of MyObject (because this information is compiled into the MyList class).
but
List<MyObject> x = new ArrayList<MyObject>();
Reflection will not tell you anything useful (because the ArrayList class knows nothing about MyObject).
The general idea is that if you create a named or anonymous class that is a subclass of a generic type with particular types for the type parameters, then the subclass is not generic and not subject to type erasure. Assuming that you can get hold of the Class object for the subclass, you can use reflection on that object to find out what the parameter types are.
When you think about it, this is not really an "exception" to the erasure rule. Rather, it is arranging that the class in question is not generic by explicitly reifying it.
How to get class object of a generic interface?
For example, Boolean.class, Date.class.
But List<Boolean>.class doesn't seem to be syntax-valid.
Just write List.class. List<Boolean> is not of a different type, at runtime. The generic type only exists at compile time. So this imaginary List<Boolean>.class would not exist to be used in your program.
There is no way to programmatically access the generic type, since it is not present in the byte code. It is only to help the compiler.
Due to type erasure, your List<Boolean> will be converted to a simple raw List at runtime, thus, your best bet is to use List.class.