Выводящий тип аргументов класса в универсальном интерфейсе Java - PullRequest
0 голосов
/ 12 декабря 2018

Обратите внимание: Я провел целый день, чтобы убедиться, что это не дубликат.Большинство решений, которые я видел, основаны на вызове 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);
    }
}

СейчасЯ хочу, чтобы возможность выводить универсальные типы любых экземпляров этих классов.Я пытаюсь добиться этого методом inferTypes в Main.java следующим образом:

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

Я не могу понять, как получить конкретные классы для второго случая.Любая помощь будет высоко ценится.

1 Ответ

0 голосов
/ 12 декабря 2018

В случае GenericClass<K, V> в файле класса нет информации, определяющей тип.Это происходит из-за стирания типа.

Лучшее, что вы можете сделать, это вывести тип из содержимого карты.Если вам нужно записать тип, который вы можете сделать

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; }

, то есть вам нужно явно хранить типы.

...