【发布时间】:2019-03-19 11:15:46
【问题描述】:
我有一个名为“Test”的类,我将其传递给Test.class 的方法,该方法的类型为Class<T> clazz。
我需要从该 clazz 变量调用 Test 类的 toString() 方法。我们可以在不将 clazz 类型转换为 Test 的情况下使用反射来做到这一点吗?
【问题讨论】:
标签: java android generics reflection
我有一个名为“Test”的类,我将其传递给Test.class 的方法,该方法的类型为Class<T> clazz。
我需要从该 clazz 变量调用 Test 类的 toString() 方法。我们可以在不将 clazz 类型转换为 Test 的情况下使用反射来做到这一点吗?
【问题讨论】:
标签: java android generics reflection
首先从 clazz 变量创建对象,然后调用该对象的toString() 方法。
clazz.newInstance().toString();
如果你有一个默认的构造函数,那么它也可以工作:
clazz.getConstructor().newInstance().toString();
更新: 如果你想制作通用的测试功能,那么你必须像这样实现测试功能。
public void TestToString(Object obj,String expectedVal){
assertEquals(obj.toString(),expectedVal);
}
【讨论】:
toString() 方法不需要进行类型转换。
toString() 是存在于 Object 上的方法,因此您可以在任何对象上调用它而无需使用反射。您期望使用反射有什么好处?
toString()function 在Test 类中被覆盖了吗?
不能在Class 参数上调用方法。
这只是对类的描述,但要调用方法,您将需要类的实例化。
您可以:
- 使用反射创建 .class 参数的实例以在
或
上调用方法
- 使用反射调用实例上的方法。
但最重要的是,您需要一个实例。
还有一点评论(如 Joachim Sauer 所述):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
如您所见,无论是调用标准方式还是通过泛型,甚至更糟糕的反射,都会产生相同的逻辑。
我希望这能启发你(和其他人);)
【讨论】: