I just learned about this fine looking syntax
Collections.<String>emptyList()
to get an empty List
with elements which are supposedly of type String
. Java's source looks like this:
public static final List EMPTY_LIST = new EmptyList<Object>();
:
public static final <T> List<T> emptyList() {
return (List<T>) EMPTY_LIST;
}
Now if I code a method in that way where the generic type does not appear in the parameter list, is there any way how I can access the actual class that becomes T
?
I'm saying, up to now my approach to code the same thing would have been
private <T> T get(String key, Class<T> clazz) {
// here I can do whatever I want with clazz, e.g.:
return clazz.cast(value);
}
If I removed the clazz
-parameter I wouldn't be able to do the cast()
. Obviously I could do
return (T) value;
but that gives me the usual warning Type safety: Unchecked cast from Object to T
. Ok, @SuppressWarnings("unchecked")
helps here, but actually I want to do something with the intended return type of the method. If I add a local variable
T retValue;
I'd have to initialise it with something, null
doesn't help. After I assign it like
@SuppressWarnings("unchecked")
T retValue = (T) value;
I could do, e.g.
retValue.getClass().getName()
but if the cast fails I end up with no information about T
again.
Since Java (or at least my Java 6) does not have the generic info any more during runtime, I currently can't think of a way to do this. Is there a way? Or do I have to stick with my "old" approach here?
Please note that the example I lined out is very simple and doesn't make much sense. I want to do more complicated stuff here, but that's out of the scope.
You can get around the superfluous reference by providing a generic static factory method. Something like public static <T> GenericClass<T> of(Class<T> type) {...} and then call it as such: GenericClass<String> var = GenericClass. of(String. class) .
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.
Yes, you can define a generic method in a non-generic class in Java.
Yes, in this case, inheritance is a better solution than composition as you have it, because a StackInteger is a Stack .
If you want the generic type at runtime you need to either have it as a field or create a sub-class of a type for a specific combination of types.
e.g.
List<String> list = new ArrayList<String>() {}; // creates a generic sub-type
final Class type = (Class) ((ParameterizedType) list.getClass()
.getGenericSuperclass()).getActualTypeArguments()[0];
System.out.println(type);
prints
class java.lang.String
You can't, unfortunately. All generics and type parameters are erased in runtime. So in runtime the type of your T
is simply Object
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