Если в качестве имени типа универсального класса используется строка, как я могу создать экземпляр во время выполнения.Если это невозможно, есть ли другой способ? - PullRequest
0 голосов
/ 17 октября 2018

Пользователь поддерживает userType и userFunction с помощью конфигурации:

{"userType": "com.user.Person", "userFunction": "com.user.userFunction"}

мы ожидаем получить данные для пользователя и передать данные для userFunction:

public class DataConsumer<T> {
    //get data from some place, such as kafka
    T data;
}
process() {
    String userType = userInput();
    DataConsumer<userType> dataConsumer = new DataConsumer<userType>(); // error because generic class's type name don't support String or Class 
    userFunction(dataConsumer.data); // We get this function by reflection
}

// This is ok in the user side
userFunction(userType data) {
    data;
}

Как я могу реализовать эту функцию без ошибок?Если это невозможно, есть ли другой способ?

Наконец, я использую Object для обозначения всех имен типов.Но пользователь должен преобразовать тип объекта в userType вручную.Есть ли лучший способ?

{
    String userType = userInput();
    DataConsumer<Object> dataConsumer = new DataConsumer<Object>(); // ok
    userFunction(dataConsumer.data); 
}

userFunction(Object data) {
    (userType)data;
}

Ответы [ 2 ]

0 голосов
/ 17 октября 2018

Ах, вы должны знать, что дженерики в java в большинстве случаев являются только синтаксическим сахаром в компиляторе, поэтому, если вы не знаете тип времени выполнения, просто используйте подстановочный или необработанный тип:
MyClass<?> myClass = new MyClass<>();, MyClass myClass = new MyClass();
Но если пользовательский ввод всегда имеет известный тип, такой как String, тогда вы можете просто сделать:
MyClass<String> myClass = new MyClass<>();
Вы также можете создать универсальный конструктор в своем классе следующим образом:

public class MyClass<T> {
    T data;
    public <T> MyClass(T data) {this.data = data;}
}

Таким образом, универсальный тип будет относиться к типу данных, которые вы передали ему - но он существует только во время компиляции, во время выполнения Java игнорирует все обобщенные здесь, как это допустимый код Java:

List<String> strings = new ArrayList<>();
strings.add(“a”);
List<Integer> integersKindOf = (List)strings;
integersKindOf.remove(“a”);

Java сохраняет толькоуниверсальный тип полей, суперклассы (class MyMap extends HashMap<String, Integer> - вы можете получить этот супертип с универсальными параметрами) и методы.Но они не используются во время выполнения, но для чтения этого типа можно использовать отражения.
Для локальных переменных это невозможно и будет бесполезно из-за стирания этого типа.

Существует также общий шаблон для unsafe универсальное приведение, но вы должны быть очень осторожны, когда его использовать:

public <T> T doSomething(String type) {
    return (T) Class.forName(type).newInstance();
}

, и тогда это можно использовать так:
ArrayList<Whatever> list = doSomething("java.util.ArrayList");
но этоможет также использоваться следующим образом:
Integer list = doSomething("java.util.ArrayList");
И это вызовет исключение во время выполнения, и именно поэтому это очень небезопасно.

0 голосов
/ 17 октября 2018

Вы можете использовать Reflection API для получения экземпляра классов, методов и полей;

Сначала вы можете получить класс, используя

 Class c = Class.forName("Class Name");

Вы можете получить методы из этого класса.используя

 c.getDeclaredMethod("Method Name");

и то же самое касается полей

 c.getDeclaredField("Field Name");
...