简体   繁体   中英

Return a Class instance with its generic type

Here's a simple example that demonstrates a type-erasure-related issue I am running into. I have a class like this:

public abstract class AbstractHandler<T> {

    ...
    public abstract Class<T> handledType();
}

Then I have this implementation:

public class ConcreteHandler extends AbstractHandler<Map<String, List<Thing>>> {

    @Override
    public Class<Map<String, List<Thing>>> handledType() {
        //what do I return here?!
    }
}

I can't return Map<String, List<Thing>>.class , since that's not even valid syntactically. I tried making the generic type-parameter in the subtype to be HashMap<String, List<Thing>> and then returning new HashMap<String, List<Thing>>().getClass() , but that doesn't work because the return type of Class<T>#getClass() is Class<? extends T> Class<? extends T> . I looked at TypeToken from Guava, and the getRawType method seemed promising, but it returns Class<? super T> Class<? super T> .

I have a workaround for the time being that looks like this:

public class ThingListMap {
    private Map<String, List<Thing>> thingListMap;

    ...
}

and I just use ThingListMap as the generic type-parameter.

Another possible workaround is to perform a forced cast:

public Class<Map<String, List<Thing>>> handledType() {
    return (Class<Map<String, List<Thing>>>) new HashMap<String, List<Thing>>().getClass();
}

Is there a more-elegant way to do this?

EDIT: In response to one of the answers, I cannot change the signature of the handledType method since I do not own or control its source.

For some reason, Java doesn't allow you to cast Map.class directly to Class<Map<String, List<Thing>>> . It's an unchecked cast anyway.

But it's legal to cast it twice, first to Class<?> , then to Class<Map<String, List<Thing>>> .

return (Class<Map<String, List<Thing>>>) (Class<?>) Map.class;

Being an unchecked cast, you may want to add @SuppressWarnings("unchecked") .

Guava's approach to this is to use TypeToken s. Your class would become

public abstract class AbstractHandler<T> {
    public TypeToken<T> handledType();
}

public class ConcreteHandler extends AbstractHandler<Map<String, List<Thing>>> {
    @Override
    public TypeToken<Map<String, List<Thing>>> handledType() {
        return new TypeToken<Map<String, List<Thing>>>() {};
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM