#java #android #generics #reflection
#java #Android #обобщения #отражение
Вопрос:
У меня есть класс с именем «Test», который я передаю методу как Test.class
который будет иметь тип Class<T> clazz
.
Мне нужно вызвать метод toString () класса Test из этой переменной clazz. Можем ли мы сделать это, используя отражение без приведения типов clazz для тестирования?
Ответ №1:
Сначала создайте объект из переменной clazz, а затем вызовите toString()
метод этого объекта.
clazz.newInstance().toString();
Если у вас есть конструктор по умолчанию, то он также будет работать :
clazz.getConstructor().newInstance().toString();
Обновлено :
Если вы хотите создать общую тестовую функцию, то вам нужно реализовать тестовую функцию следующим образом.
public void TestToString(Object obj,String expectedVal){
assertEquals(obj.toString(),expectedVal);
}
Комментарии:
1. Я не хочу приводить его к типу. Я хочу вызвать его, используя отражение.
2. @The90sArtist смотрите обновленный ответ. вам не нужно приводить тип для вызова
toString()
метода.3. @The90sArtist: почему вы хотите принудительно использовать отражение?
toString()
это метод, который существует наObject
, поэтому вы можете просто вызвать его для любого объекта без использования отражения. Какое преимущество вы ожидаете от использования отражения?4. Я попробовал вышеупомянутое решение, оно все еще печатает com.artist. Тест@61a0f38
5. @The90sArtist Вы уверены, что ваша
toString()
функция переопределена вTest
классе?
Ответ №2:
Невозможно вызвать метод для Class
параметра. Это всего лишь описание класса, но для вызова метода вам потребуется создание экземпляра класса.
Вы можете:
— использовать отражение для создания экземпляра параметра .class для вызова метода
или
— используйте отражение для вызова метода в экземпляре.
Но суть в том, что вам НУЖЕН экземпляр.
Также небольшое замечание (как уже было сказано Йоахимом Зауэром):
toString()
метод существует в Object
классе, и все расширяет Object
класс, поэтому он всегда доступен.
Нет необходимости в отражении, обобщениях или приведении. Вы просто переопределяете этот метод в своем классе, и все готово.
Небольшой пример, демонстрирующий различные способы вызова toString():
public class Test {
private String name = "unnamed";
public Test() {}
public Test(String name) {
this.name = name;
}
public void setName(String name) {
this.name = name;
}
public String toString() {
return name;
}
public static <T> T doReflectionCreateToString(Class<T> clazz) {
try {
T newT = clazz.getConstructor(String.class).newInstance("Name 2");
System.out.println("Created by reflection: " newT);
return newT;
} catch (InstantiationException | IllegalAccessException | IllegalArgumentException | InvocationTargetException
| NoSuchMethodException | SecurityException e) {
e.printStackTrace();
}
return null;
}
@SuppressWarnings("unchecked")
public static <T, E> E doReflectionCall(T obj, String methodName, Object[] arguments, Class<E> returnClazz) {
try {
Class<?> clazz = obj.getClass();
Method myMethod = clazz.getDeclaredMethod(methodName);
return (E) myMethod.invoke(obj, arguments);
} catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException | NoSuchMethodException | SecurityException e) {
e.printStackTrace();
}
return null;
}
public static <T> void doGenericToString(T obj) {
System.out.println("toString by Generic way: " obj);
}
public static void main(String[] args) {
Test t = new Test();
t.setName("Name 1");
System.out.println("toString by standard way: " t);
doGenericToString(t);
System.out.println("Called by reflection: " doReflectionCall(t, "toString", new Object[]{}, String.class));
Test newT = doReflectionCreateToString(Test.class);
System.out.println("Returned by reflection: " newT);
}
}
Который выводит:
toString стандартным способом: Имя 1
toString универсальным способом: Имя 1,
вызываемое отражением: Имя 1,
созданное отражением: Имя 2,
возвращаемое отражением: Имя 2
Как вы можете видеть, независимо от того, вызывается ли он стандартным способом или с помощью обобщений или даже худшего отражения, все результаты в одной и той же логике.
Я надеюсь, что это просветит вас (и кого-то еще) 😉