【问题标题】:Inferring type of class arguments in Java generic interface在 Java 泛型接口中推断类参数的类型
【发布时间】:2018-12-12 11:37:46
【问题描述】:

请注意:我花了一整天的时间确保这不是重复的。我见过的大多数解决方案都依赖于调用clazz.getGenericSuperclass(),然后调用getActualTypeArguments(),但这并不能解决我的问题,因为通用超类是java.lang.Object

请继续阅读。


现在解决问题

我想实现一个提供通用接口的库。

public interface MyInterface<K, V> {
    public V get(K key);
    public void set(K key, V value);
}

然后用户可以在具体的类中实现它,例如:

import java.util.HashMap;

public class ConcreteClass implements MyInterface<String, Integer> {
    private HashMap< String, Integer > myMap;

    public ConcreteClass() {
    this.myMap = new HashMap< >();
    }

    public Integer get(String key) {
    return myMap.get(key);
    }

    public void set(String key, Integer value) {
    myMap.put(key, value);
    }
}

或者他们可能会实现另一个泛型类,例如:

import java.util.HashMap;

public class GenericClass<K, V> implements MyInterface<K, V> {
    private HashMap<K, V> myMap;

    public GenericClass() {
    this.myMap = new HashMap<K, V>();
    }

    public V get(K key) {
    return myMap.get(key);
    }

    public void set(K key, V value) {
    myMap.put(key, value);
    }
}

现在,我希望能够推断这些类的任何实例的泛型类型。我正在尝试在Main.java 中的inferTypes 方法中实现这一点,如下:

import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;

public class Main {
    private static <K, V> void inferTypes(MyInterface<K, V> mi) {
        Class<?> clazz = mi.getClass();

        // Should print whether "ConcreteClass" or "GenericClass"
        System.out.println(clazz.getName());

        Type[] ifaces = clazz.getGenericInterfaces();
        for (Type iface : ifaces) {
            // Should print "MyInterface<String, Integer>"
            System.out.println(iface.toString());
            Type[] types = ((ParameterizedType) iface).getActualTypeArguments();
            for (Type type : types) {
                // Should print "String" and then "Integer"
                System.out.println(type.toString());
            }
        }
    }

    public static void main(String[] args) {
        // Someone instantiates the class
        ConcreteClass cc = new ConcreteClass();
        // And I can successfully infers the type
        Main.inferTypes(cc);

        System.out.println("-------");

        // Someone instantiates the generic class
        GenericClass<String, Integer> gc = new GenericClass<>();
        // And I can't infer the types this time
        Main.inferTypes(gc);
    }
}

它适用于ConcreteClass 的实例,但不适用于GenericClass 的实例。

ConcreteClass
MyInterface<java.lang.String, java.lang.Integer>
class java.lang.String
class java.lang.Integer
-------
GenericClass
MyInterface<K, V>
K
V

我不知道如何为第二种情况获取具体的类。任何帮助将不胜感激。

【问题讨论】:

  • @AnkurChrungoo,没有任何效果。此外,由于这些类将由库的用户实例化,因此我无法强制执行任何特定的实例化方式。
  • 我假设你已经浏览过这个链接:stackoverflow.com/questions/53690045/…
  • @AnkurChrungoo,是的。正如我在顶部的注释中提到的那样。 getGenericSuperclass() 方法不起作用,因为它返回类型为 java.lang.Object 的对象,我无法将其转换为 ParameterizedType。给我一个编译时警告unchecked cast;和运行时ClassCastException
  • 是的,但实际上我的意思是使用库 github.com/leangen/… 。在这里可能会有所帮助。
  • 我不知道这个。我去看看,谢谢但我不确定它在我的生产环境中是否可用。所以我可能不得不继续寻找使用标准 Java 库的解决方案。

标签: java generics type-inference


【解决方案1】:

GenericClass&lt;K, V&gt; 的情况下,类文件中没有确定类型的信息。这是由于类型擦除造成的。

你能做的最好的事情就是从地图的内容中推断出类型。如果需要记录类型可以做

public class GenericClass<K, V> implements MyInterface<K, V> {
    private final Map<K, V> myMap;
    private final Class<K> keyClass;
    private final Class<V> valueClass

    public GenericClass(Class<K> keyClass, Class<V> valueClass) {
        this.myMap = new HashMap<K, V>();
    }

    public Class<K> getKeyClass() { return keyClass; }
    public Class<V> getValueClass() { return valueClass; }

即您需要明确存储类型。

【讨论】:

  • 再补充一句,如果你的设计依赖于此,那么 10 的 9 次设计就是错误的。
  • @Michael 我用过它,但仅限于非常特殊的情况。例如使序列化更加紧凑。
  • @Michael,您能详细说明一下吗?因为正如 Peter 在他的评论中添加的那样,我需要这种推断来确保序列化期间的类型安全。
  • @N.CHATURV3DI 它可能是必要的,但是人们在 Stack Overflow 上询问如何做这样的事情的次数与实际需要/必要的频率/最佳是天壤之别。
  • @N.CHATURV3DI 类型擦除适用于所有类型。如果您想确保接口的实现者可以返回类型,请将方法添加到他们必须实现的接口中。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-08-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多