【问题标题】:Call Object's toString() method from .class (Class<?>)从 .class (Class<?>) 调用 Object 的 toString() 方法
【发布时间】:2019-03-19 11:15:46
【问题描述】:

我有一个名为“Test”的类,我将其传递给Test.class 的方法,该方法的类型为Class&lt;T&gt; clazz

我需要从该 clazz 变量调用 Test 类的 toString() 方法。我们可以在不将 clazz 类型转换为 Test 的情况下使用反射来做到这一点吗?

【问题讨论】:

    标签: java android generics reflection


    【解决方案1】:

    首先从 clazz 变量创建对象,然后调用该对象的toString() 方法。

    clazz.newInstance().toString();
    

    如果你有一个默认的构造函数,那么它也可以工作:

    clazz.getConstructor().newInstance().toString();
    

    更新: 如果你想制作通用的测试功能,那么你必须像这样实现测试功能。

    public void TestToString(Object obj,String expectedVal){
        assertEquals(obj.toString(),expectedVal);
      }
    

    【讨论】:

    • 我不想打字。我想用反射来调用它。
    • @The90sArtist 查看更新后的答案。调用toString() 方法不需要进行类型转换。
    • @The90sArtist:为什么要强制使用反射? toString() 是存在于 Object 上的方法,因此您可以在任何对象上调用它而无需使用反射。您期望使用反射有什么好处?
    • 我尝试了上面的解决方案,它仍然在打印 com.artist.Test@61a0f38
    • @The90sArtist 你确定toString()function 在Test 类中被覆盖了吗?
    【解决方案2】:

    不能在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

    如您所见,无论是调用标准方式还是通过泛型,甚至更糟糕的反射,都会产生相同的逻辑。
    我希望这能启发你(和其他人);)

    【讨论】:

      猜你喜欢
      • 2016-03-28
      • 1970-01-01
      • 2014-12-12
      • 1970-01-01
      • 2015-09-17
      • 2021-09-23
      • 1970-01-01
      • 1970-01-01
      • 2014-02-22
      相关资源
      最近更新 更多