While I know you cannot actually get the type of a generic at runtime because of type erasure, I was wondering if it is possible to get it at compile time.
class ObjectHandle<T extends ObjType> {
T obj;
void setObj(T o) {
obj = o;
}
}
class ObjType {}
class SubObjType extends ObjType {}
...
ObjectHandle<SubObjType> handle = new ObjectHandle<SubObjType>();
...
ObjType obj = [method that returns an ObjType];
if(obj instanceof [handle's generic class, here SubObjType]) {
handle.setObj(obj); // cast???
}
Here the compiler knows the type of the generic of handle
and what I want is something so I don't have to change the type of handle
and the instanceof
check (and the cast) when I decide to change the class (in the code, not at runtime of course).
Since generic types are subjected to erasure, you will need to specify the java.lang.Class somewhere in the code. One way is to pass it to a generic method:
ObjType obj = /*...*/;
handleObj(obj, SubObjType.class);
// ...
private <T extends ObjType> void handleObj(ObjType obj,
ObjectHandle<T> handle,
Class<T> handleableObjClass) {
if (handleableObjClass.isInstance(obj)) {
handle.setObj(handleableObjClass.cast(obj));
}
}
If you don't know what subclasses of ObjType you're looking for, you will need to add a reifiable Class property to ObjectHandle, similar to how java.util.EnumSet and java.util.EnumMap do it:
class ObjectHandle<T extends ObjType> {
T obj;
private final Class<T> objectClass;
ObjectHandle(Class<T> cls) {
objectClass = Objects.requireNonNull(cls);
}
Class<T> getObjectClass() {
return objectClass;
}
void setObj(T o) {
obj = o;
}
}
// ...
ObjectHandle<SubObjType> handle = new ObjectHandle<SubObjType>();
// ...
ObjectType obj = /*...*/;
if (handle.getObjectClass().isInstance(obj)) {
handle.setObj(handle.getObjectClass().cast(obj));
}