How to determine the class of a generic type?
Still the same problems : Generic informations are erased at runtime, it cannot be recovered. A workaround is to pass the class T in parameter of a static method :
public class MyGenericClass<T> {
private final Class<T> clazz;
public static <U> MyGenericClass<U> createMyGeneric(Class<U> clazz) {
return new MyGenericClass<U>(clazz);
}
protected MyGenericClass(Class<T> clazz) {
this.clazz = clazz;
}
public void doSomething() {
T instance = clazz.newInstance();
}
}
It's ugly, but it works.
How do I get a class instance of generic type T?
The short answer is, that there is no way to find out the runtime type of generic type parameters in Java. I suggest reading the chapter about type erasure in the Java Tutorial for more details.
A popular solution to this is to pass the Class
of the type parameter into the constructor of the generic type, e.g.
class Foo<T> {
final Class<T> typeParameterClass;
public Foo(Class<T> typeParameterClass) {
this.typeParameterClass = typeParameterClass;
}
public void bar() {
// you can access the typeParameterClass here and do whatever you like
}
}
Check if a class is generic type
From the Class<?> object
you can check cls.getTypeParameters()
.
From a generic class you get a nonempty array of TypeVariable
.
From a non-generic class you get an empty array.
E.g.
java.util.List.class.getTypeParameters()
TypeVariable[1] { E }
String.class.getTypeParameters()
TypeVariable[0] {}
How to check if a generic type implements a specific type of generic interface in java?
Java implements erasure, so there's no way to tell on runtime if genericObject
is an instance of Set<String>
or not. The only way to guarantee this is to use bounds on your generics, or check all elements in the set.
Compile-time Generic Bounds
Using bounds checking, which will be checked at compile-time:
public <T extends SomeInterface> void genericMethod(Set<? extends T> tSet) {
// Do something with tSet here
}
Java 8
We can use streams in Java 8 to do this natively in a single line:
public <T> void genericMethod(T t) {
if (t instanceof Set<?>) {
Set<?> set = (Set<?>) t;
if (set.stream().allMatch(String.class:isInstance)) {
Set<String> strs = (Set<String>) set;
// Do something with strs here
}
}
}
Java 7 and older
With Java 7 and older, we need to use iteration and type checking:
public <T> void genericMethod(T t) {
Set<String> strs = new HashSet<String>();
Set<?> tAsSet;
if (t instanceof Set<?>) {
tAsSet = (Set<?>) t;
for (Object obj : tAsSet) {
if (obj instanceof String) {
strs.add((String) obj);
}
}
// Do something with strs here
} else {
// Throw an exception or log a warning or something.
}
}
Guava
As per Mark Peters' comment below, Guava also has methods that do this for you if you can add it to your project:
public <T> void genericMethod(T t) {
if (t instanceof Set<?>) {
Set<?> set = (Set<?>) t;
if (Iterables.all(set, Predicates.instanceOf(String.class))) {
Set<String> strs = (Set<String>) set;
// Do something with strs here
}
}
}
The statement, Iterables.all(set, Predicates.instanceOf(String.class))
is essentially the same thing as set instanceof Set<String>
.
Java Generic Class - Determine Type
I've used a similar solution to what he explains here for a few projects and found it pretty useful.
http://blog.xebia.com/2009/02/07/acessing-generic-types-at-runtime-in-java/
The jist of it is using the following:
public Class returnedClass() {
ParameterizedType parameterizedType = (ParameterizedType)getClass()
.getGenericSuperclass();
return (Class) parameterizedType.getActualTypeArguments()[0];
}
Java: how do I get a class literal from a generic type?
You can't due to type erasure.
Java generics are little more than syntactic sugar for Object casts. To demonstrate:
List<Integer> list1 = new ArrayList<Integer>();
List<String> list2 = (List<String>)list1;
list2.add("foo"); // perfectly legal
The only instance where generic type information is retained at runtime is with Field.getGenericType()
if interrogating a class's members via reflection.
All of this is why Object.getClass()
has this signature:
public final native Class<?> getClass();
The important part being Class<?>
.
To put it another way, from the Java Generics FAQ:
Why is there no class literal for concrete parameterized types?
Because parameterized type has no exact runtime type representation.
A class literal denotes a
Class
object that represents a given type.
For instance, the class literal
String.class
denotes theClass
object that represents the type
String
and is identical to the
Class
object that is returned when
methodgetClass
is invoked on a
String
object. A class literal can
be used for runtime type checks and
for reflection.Parameterized types lose their type
arguments when they are translated to
byte code during compilation in a
process called type erasure . As a
side effect of type erasure, all
instantiations of a generic type share
the same runtime representation,
namely that of the corresponding raw
type . In other words, parameterized
types do not have type representation
of their own. Consequently, there is
no point in forming class literals
such asList<String>.class
,
List<Long>.class
andList<?>.class
, since no suchClass
objects exist.
Only the raw typeList
has aClass
object that represents its runtime
type. It is referred to as
List.class
.
Related Topics
Explicitly Calling a Default Method in Java
Strings Are Objects in Java, So Why Don't We Use 'New' to Create Them
What's the Difference Between Map() and Flatmap() Methods in Java 8
How to Obtain Method Parameter Name Using Java Reflection
Can't Compile Project When I'm Using Lombok Under Intellij Idea
What Does Swingutilities.Invokelater Do
How to Check If a Single Character Appears in a String
Very Confused by Java 8 Comparator Type Inference
Loading Images from Jars for Swing HTML
How to Call a Static Method in Jsp/El
Handling Passwords Used for Auth in Source Code
Which Java Collection Should I Use
Calculate Size of Object in Java
Simpledateformat Parsing Date with 'Z' Literal