Вызов метода toString() объекта из .class (Класс)

#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

Как вы можете видеть, независимо от того, вызывается ли он стандартным способом или с помощью обобщений или даже худшего отражения, все результаты в одной и той же логике.
Я надеюсь, что это просветит вас (и кого-то еще) 😉