无法从Class对象获取Type令牌?

时间:2018-12-20 03:50:48

标签: java generics syntactic-sugar

假设我有一个由各种类实现的通用接口。

public interface MyInterface<K, V> {
    // Some method declarations
    // ...
    // But owing to Java type erasure, we also have...
    Class<K> getKClass();
    Class<V> getVClass();
}

现在,我正在使用对象存储来获取实现MyInterface的类的具体实例。而且在编写代码时,我还不知道参数KV的类型。但是,可以访问预先存储的相应Class对象。现在,我可以在请求工厂时使用它们。

public MyInterface getObjectFromStore(String uniqueKey, 
      Class kClazz, Class vClazz) {
    MyInterface concreteInstance = MyClassWarehouse.retrieveObject(uniqueKey);

    // Perform type checks.
    boolean kMismatch = !kClazz.isAssignableFrom(concreteInstance.getKClass());
    boolean vMismatch = ...;
    // Mismatch handling...
    ...

    // Everything's okay
    return concreteInstance;
}

在我看来,如果我可以将方法编写为:

public <K, V> MyInterface<K, V> getObjectFromStore(String uniqueKey) {
    try {
        MyInterface<K, V> concreteInstance = MyClassWarehouse.retrieveObject(uniqueKey);
        return concreteInstance;
    } catch (ClassCastException cce) {
        // Better way to handle type mismatch
        ...
    }
}

但这要求我在编写代码时了解这些类。

MyInterface<String, Double> retrievedObject = getObjectFromStore("key123");

由于我只有类对象,因此必须使用第一种“分类器”方法。特别是:

// Must use this...
MyInterface retrievedObject = getObjectFromStore("key123", kClazz, vClazz);

// ... because this (or anything equivalent) is not possible.
MyInterface<kClazz, vClazz> retrievedObject = getObjectFromStore("key123");

在我看来,由于类型不是Java中的善意对象,因此无法从类对象KV中获取类型标记kClazzvClazz一种可以实现第二种方法的方式。但是,语法糖会很好。

还有其他原因无法启用此功能吗?

1 个答案:

答案 0 :(得分:0)

如果您放弃编译时检查而转而使用运行时检查,则将需要来自两个源的运行时类型对象以进行任何比较。

因此,是的,最简单的方法是指定Class对象的两端。在简单的情况下。

<T> void put(Class<T> t, T object);
<T> T get(Class<T> t);

添加特定的双重参数化类型(Java中没有更高类型的类型),这两个类型和一个键(对于严格的编程为boo)。

<K,V> void put(Class<K> k, Class<V> v, Key key, My<K,V> object);
<K,V> My<K,V> get(Class<K> k, Class<V> v, Key key);

有机会将三个关键对象组合为一个。

public final class MyKey<K,V> {
    public static of(Class<K> k, Class<V> v, SimpleKey key) {
        ....
    }
    ...
}
<K,V> void put(MyKey<K,V> key, My<K,V> object);
<K,V> My<K,V> get(MyKey<K,V> key);

或者,您可以寻找不同的类对象源。它们可以从方法签名中获得。

public interface MyReceiver<K,V> {
    void accept(My<K,V> object);
}
/** @param receiver Runtime type should specialise type parameters. */    
void get(MyReceiver<?,?> receiver); 

({MyReciever<?,?>可以是标准的Consumer<? extends MyReciever<?,?>>。)

您可以将其他简单键添加为get的参数(对lambda友好),MyReceiver上的方法,acceptMyReceiver上的注释,或从MyReceiver中删除该方法,并使用其运行时类型用作方法名称的任何名称(可能加上注释以查找所需的方法)。

实际上,这种在界面中指定所需类型的方法比旧式异构地图更现代

(请注意,“存储库”是您仓库的标准术语。)