I come from a C# world and I've just learned about erasure in Java, which put me a bit off. Is there really no way to distinguish SomeGenericInstance<String>
from SomeGenericInstance<Integer>
runtime in Java?
I'm asking because I've implemented a super simple pub-sub framework and I wanted to have a generic class GenericMessage<T>
. It's essential not to send GenericMessage<String>
to listeners of GenericMessage<Integer>
. I tried implementing it by having a List of key-value pairs where the key is the Class
object representing the type of the message. But this code line yields true
which is a problem...:
new GenericMessage<Integer>().getClass.equals(new GenericMessage<String>().getClass())
As far as I am aware, sorry, it is simply impossible.
You can access it using next trick:
public class Example<T> {
Class<T> genericType;
public Example(Class<T> genericType) {
this.genericType= genericType;
}
public static void main(String args[]) {
Example<Integer> ex1 = new Example<>(Integer.class);
Example<String> ex2 = new Example<>(String.class);
System.out.println(ex1.genericType);
System.out.println(ex2.genericType);
}
}
Output:
class java.lang.Integer
class java.lang.String
You can do it using Java Reflection. Don't know if it's always a good idea, but it's surely possible. Here's an example:
public class Test{
private List<String> list;
public static void main(String[] args) throws Exception{
Field field = Test.class.getDeclaredField("list");
Field f = field.getGenericType().getClass().getDeclaredField("actualTypeArguments");
f.setAccessible(true);
Type[] genericTypes = (Type[]) f.get(field.getGenericType());
System.out.println(genericTypes[0]);
}
}
Or you can cast directly to ParameterizedType, if it seems any better to you:
public class Test{
private List<String> list;
public static void main(String[] args) throws Exception{
Field field = Test.class.getDeclaredField("list");
ParameterizedType parameterizedType = (ParameterizedType) field.getGenericType();
Type[] actualTypes = parameterizedType.getActualTypeArguments();
System.out.println(actualTypes[0]);
}
}
Both examples print: class java.lang.String
Now just to leave a more complete answer, the same can be done for a Map. As you can see the getActualTypeArguments()
method returns a Type[]
and for a Map, the key type would be index 0, and the value type would be index 1. Example:
public class Test{
private Map<String, Integer> map;
public static void main(String[] args) throws Exception{
Field mapField = Test.class.getDeclaredField("map");
ParameterizedType mapParameterizedType = (ParameterizedType) mapField.getGenericType();
Type[] actualMapTypes = mapParameterizedType.getActualTypeArguments();
System.out.println(actualMapTypes[0]);
System.out.println(actualMapTypes[1]);
}
}
Prints:
class java.lang.String
class java.lang.Integer
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With