繁体   English   中英

Java Generics:从参数中获取返回类型

[英]Java Generics: getting return type from parameter

这是一个奇怪的问题。 我不认为有解决方案,但我想我还是会问。

假设我有一个枚举:

public enum Key {
    RED(String.class),
    GREEN(Integer.class),
    BLUE(Short.class);

    private Class<?> expectedType;

    Key(Class<?> expectedType) { this.expectedType = expectedType; }
    public Class<?> getExpectedType() { return expectedType; }
}

我想使用Key枚举中的“ expectedType ”字段作为方法的返回类型。 看:

public class Cache {

    private static Map<Key, Object> cache = new HashMap<>();

    public void put(Key key, Object value) {
        // Easy to validate that 'value' is of type key.getExpectedType()...
    } 

    public <T> T get(Key key) {
        Object value = cache.get(key);
        // TODO need to define <T> as key.getExpectedType(). How?
        
    }
}

看到那个 TODO 了吗? 我想让get()定义由key参数定义的“expectedType”的返回类型。 例如,如果key参数是REDget()方法将返回一个 String 并且您可以编写:

    String s = cache.get(Key.RED);

有没有办法做到这一点? 我认为没有,但我很想听听一个聪明的解决方案。

枚举不支持 generics,但您可以使用常规 class 作为通用伪枚举:

public class Key<T> {
    public static final Key<String> RED = new Key<>(String.class);
    public static final Key<Integer> GREEN = new Key<>(Integer.class);
    public static final Key<Short> BLUE = new Key<>(Short.class);

    private final Class<T> expectedType;

    private Key(Class<T> expectedType) { this.expectedType = expectedType; }
    public Class<T> getExpectedType() { return expectedType; }
}

public class Cache {

    private Map<Key<?>, Object> cache = new HashMap<>();

    public <T> void put(Key<T> key, T value) {
        cache.put(key, key.getExpectedType().cast(value));
    } 

    public <T> T get(Key<T> key) {
        return key.getExpectedType().cast(cache.get(key));
    }
}

shmosel 的答案几乎可以肯定足以满足您的需求; 但是,它有一点限制,即您无法存储/检索泛型类型,因为您无法获得泛型类型的 class 文字。

相反,您可以使用Guava 的TypeCapture类的东西:

abstract class GenericKey<T> {
  Type getExpectedType() {
    return ((ParameterizedType) getClass().getGenericSuperclass())
        .getActualTypeArguments()[0];
  }
}

这有点反光,你不应该花太多时间去看。

请注意,它是抽象的,因此您必须像这样实例化:

new GenericKey<Integer>() {}

这是创建一个GenericKey的匿名子类,这是使其与泛型类型一起工作的魔力的一部分。

然后,它基本上是一样的:

public class Cache {

    private Map<GenericKey<?>, Object> cache = new HashMap<>();

    public <T> void put(GenericKey<T> key, T value) {
        cache.put(key.getExpectedType(), value);
    } 

    public <T> T get(GenericKey<T> key) {
        return (T) cache.get(key.getExpectedType());
    }
}

现在,如果您愿意,可以使用new new GenericKey<List<Integer>() {}拥有一个GenericKey<List<Integer>>

这种方法的缺点是您无法在进出缓存的过程中检查值,因此如果您对原始类型粗心,您可能会受到堆污染。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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