Соотнесите Java тип поля и универсальный c параметр - PullRequest
0 голосов
/ 23 апреля 2020

Рассмотрим следующие классы:

class A {
    B<Integer> b;
}

class B<T> {
    T t;
}

Мне нужно написать следующий метод:

Object create(Class clazz) {
    // todo
}

, чтобы при вызове create(A.class) возвращаемое значение было экземпляром A, который содержит целое число в b.t. Естественно, у метода не должно быть никаких знаний о A, кроме его класса.

Хорошо известно, как выяснить, что тип b в A равен B<Integer>.

Я ищу способ узнать, что поле t в B предназначено для типа первого параметра типа B.

1 Ответ

1 голос
/ 23 апреля 2020

Тип поля, являющегося параметром типа, присваивается java.lang.reflect.TypeVariable. Другими словами, field.getGenericType() возвращает экземпляр TypeVariable при вызове для поля B.t.

Следующий полный пример работает для случая с игрушкой, приведенного в вопросе. Общий случай более сложен, потому что вы должны отслеживать несколько уровней параметров типа.

import java.lang.reflect.Field;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.lang.reflect.TypeVariable;

class Main {
    static class A {
        B<Integer> b;
    }

    static class B<T> {
        T t;
    }

    public static void main(String[] args) throws Exception {
        A a = (A)create(A.class);
        System.out.println(a.b.t.getClass());
        // prints java.lang.Integer
    }

    static Object create(Class<?> clazz) throws Exception {
        return create(clazz, new Type[0]);
    }

    static Object create(Class<?> clazz, Type[] typeArguments) throws Exception {
        Object object;
        if (clazz == Integer.class || clazz == int.class) {
            return 0;
        } else {
            object = clazz.newInstance();
        }
        for (Field field : object.getClass().getDeclaredFields()) {
            Type[] fieldTypeArguments = { };
            Type fieldType = field.getGenericType();
            if (fieldType instanceof TypeVariable) {
                TypeVariable<?> typeVariable = (TypeVariable<?>) fieldType;
                TypeVariable<?>[] typeParameters = typeVariable.getGenericDeclaration().getTypeParameters();
                for (int i = 0; i < typeParameters.length; i++) {
                    if (typeParameters[i] == typeVariable) {
                        fieldType = typeArguments[i];
                    }
                }
            } else if (fieldType instanceof ParameterizedType) {
                fieldTypeArguments = ((ParameterizedType) fieldType).getActualTypeArguments();
            }
            Class<?> fieldClass = null;
            if (fieldType instanceof Class) {
                fieldClass = (Class<?>) fieldType;
            } else if (fieldType instanceof ParameterizedType) {
                fieldClass = (Class<?>) ((ParameterizedType) fieldType).getRawType();
            }
            field.set(object, create(fieldClass, fieldTypeArguments));
        }
        return object;
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...