Consider the following code:
public static <T extends SomeObject> List<T> getByClassName(String className) throws GetRecordsException {
try {
Class<T> clazz = (Class<T>) Class.forName(className).asSubclass(SomeObject.class);
return getByClassName(clazz);
} catch (ClassNotFoundException e) {
throw new GetRecordsException("Failed to get class forName: " + className, e);
}
}
Eclipse is highlighting the cast (Class<T>)
with the following message:
Type safety: Unchecked cast from Class<capture#2-of ? extends SomeObject> to Class<T>
Why is this, considering that T
is supposed to be guaranteed to extend from SomeObject
in the method signature? What scenario might exist where this would be unsafe?
The caller of getByClassName
specifies T
to be any subclass of SomeObject
, but that doesn't have to be the same subclass as the one named by className
. Think of <T extends SomeObject>
as indicating that the type variable T
is another argument passed into the method call.
So for example, an unsafe usage would be foo.<SomeObjectSubclass1>getByClassName("SomeObjectSubclass2")
-- that syntax is how you specify type arguments explicitly, instead of letting them be inferred -- and then that'd return a List<SomeObjectSubclass1>
that actually contained SomeObjectSubclass2
, and everything would be a disaster.
What you could do safely is let clazz
be a Class<? extends SomeObject>
, and then return a List<? extends SomeObject
.