Java Generics: Type cast issue (ClassCastException)
-
11-10-2019 - |
Question
I'm having trouble figuring out how to properly cast a generic object in java to a type that extends the generic object.
For example, say I some setup like the following:
public class Parameters extends SomeCustomMap<String, String>
{
...
}
public class SomeCustomMap<K, V> implements Map<K, V>
{
public SomeCustomMap<K, V> getSubSet(...)
{
SomeCustomMap<K, V> subset;
...
return subset;
}
}
class ExampleApp
{
private void someMethod()
{
Parameters params;
Parameters paramsSubSet;
try
{
...
paramsSubSet = (Parameters) params.getSubSet(...);
}
catch(Exception e)
{
e.printStackTrace();
}
}
}
Running code similar to the above consistently throws a ClassCastException, the likes of which I do not fully understand. Any assitence for how to correctly set up a scenario similar to the above would be appreciated! Namely, how might I properly cast the the SomeCustomMap object that is returned from the params.getSubSet(...) method back to a Parameters object?
Thanks in advance!
Solution
You can try something like this:
public <T extends SomeCustomMap<K, V>> T getSubSet(...){
T subset = (T)this.clone();
subset.clear();
return subset;
}
creation looks a little funny - feel free to change it to whatever you want :)
As a bonus you will not need to cast :)
paramsSubSet = params.getSubSet(...)
OTHER TIPS
Your Problem is that the Subset returned by getSubSet is a of instance SomeCustomMap and not of Parameters.
This problem does not deal with generics. You will get the same problem if you did not use generics.
I don't know how you create an instance of subset but maybe you could use the template desing pattern and some generics to fix your problem.
Though I've commented asking for more information, based on what you've posted so far, I think getSubSet
is constructing a SomeCustomMap
to return (with new SomeCustomMap
) somewhere. If you don't override getSubSet
in Parameters
, then Parameters.getSubset
will return a SomeCustomMap
(the base class), not a Parameters
, so your typecast to Parameters
fails.
(Hot tip, if you override getSubSet
in the Parameters
class, you can change the return type to Parameters
and avoid the typecast.)
Generics don't inherently have anything to do with casting (save that due to the nature of erasure, generic parameters cannot be checked during a cast).
If you're getting a ClassCastException
in this case, it means that the object returned really is not an instance of Parameters
. Just before you cast, try calling
System.out.println(params.getSubSet(...).getClass());
and see what the actual run-time class of the subset is. Chances are the problem lies elsewhere, as your expectation that the subset is a Parameters object is almost certainly not correct at runtime - it's a SomeCustomMap
or some other subclass thereof.
As others have explained, the issue is that the actual object you are constructing in getSubSet()
is not an instance of Parameters
.
Here's one possible workaround. I don't love it, but it is a way to declare the method in SomeCustomMap
but have its return value be typed correctly for any subclass.
public static <T extends SomeCustomMap<K, V>> getSubSet(T fullSet)
{
T subset;
... (use fullSet instead of this)
return subset;
}