Kotlin使用反射获取泛型信息

时间:2025-02-08 13:06:15
  • 在java中,使用反射的代码实例如下:

class Student {
    String name;
    Integer age;

    public Student(String name, Integer age) {
         = name;
         = age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
         = name;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
         = age;
    }
}

abstract class BaseService<T> {
    abstract int save(T t);
}

interface StudentService<T> {
    List<T> findStudent(String name, Integer age);
}

class StudentServiceImpl extends BaseService<Student> implements StudentService<Student> {

    @Override
    int save(Student student) {
        return 0;
    }

    @Override
    public List<Student> findStudent(String name, Integer age) {
        return (new Student[]{new Student("Jack", 20), new Student("Li", 30)});
    }
}

public class JDemo {

    public static void main(String[] args) {
        StudentServiceImpl studentService = new StudentServiceImpl();
        (new Student("Tom", 30));
        ("Jack", 20);
        //反射API调用示例
        final Class<? extends StudentServiceImpl> studentServiceClass = ();
        //getClasses得到该类及其父类所有的public的内部类。
        //getDeclaredClasses得到该类所有的内部类,除去父类的。
        Class<?>[] classes = ();
        Annotation[] annotations = ();
        ClassLoader classLoader = ();
        Field[] fields = ();
        Method[] methods = ();
        try {
            methods[0].getName();
            methods[0].invoke(studentService,"jack",20);
        } catch (IllegalAccessException e) {
            ();
        } catch (InvocationTargetException e) {
            ();
        }
    }
}

通过反射,可以获取一个类的注解、方法、成员变量等。那么能不能通过反射获取到泛型信息呢?我们知道java中的泛型擦除。在程序运行时,无法得到自己本身的泛型信息。而当这个类继承了一个父类,父类中有泛型的信息时,那么可以通过getGenericSuperclass()方法得到一个父类的泛型信息。getGenericSuperclass()是Generic继承的特例,对于这种情况子类会保持父类的Generic参数类型。返回一个ParameterizedType。另外我们所说的java泛型在字节码中会被擦除,并不总是擦除为Object类型,而是擦除到上限类型。
在Kotlin也是一样的泛型机制。所以通过反射能拿到的也只能是有继承父类泛型信息的子类泛型。

class A<T>
open class C<T>

class B<T> : C<Int>()

fun fooA() {
    val parameterizedType = A<Int>():: as ParameterizedType
    val actualTypeArguments = 
    for (type in actualTypeArguments) {
        val typeName = 
        println("typeName=$typeName")
    }
}

运行fooA(),会报错

Exception in thread "main" :  cannot be cast to 
	at (:11)
	at (:24)
fun fooB(){
    val parameterizedType = B<Int>():: as ParameterizedType
    val actualTypeArguments = 
    for (type in actualTypeArguments) {
        val typeName = 
        println("typeName=$typeName")
    }
}

执行下面的代码可以运行成功。

typeName=
  • 下面通过一个简单的实例来说明Kotlin中反射怎样获取泛型代码的基本信息。

/**
 * 声明一个父类 BaseContainer
 */
open class BaseContainer<T>

/**
 * 声明一个Container 继承BaseContainer
 */
class Container<T : Comparable<T>> : BaseContainer<Int> {
    val elements: MutableList<T>

    constructor(elements: MutableList<T>) : super() {
         = elements
    }

    fun sort(): Container<T> {
        ()
        return this
    }

    override fun toString(): String {
        return "Container(elements=$elements)"
    }

}


object Test {


    @JvmStatic
    fun main(args: Array<String>) {
        //声明一个Container实例
        val container = Container(mutableListOf(1, 2, 3, 4, 5))
        // 获取Container的KClass对象引用
        val kClazz = container::class
        // KClass对象的typeParameters属性中存有类型参数的信息
        val typeParameters = 
        //typeParameters 取数组的第一个
        val kTypeParameter: KTypeParameter = typeParameters[0]
        // kTypeParameter有下面等属性
        println() // false
        println() // T
        println() // [<T>]
        println() // INVARIANT

        val constructors = 
        for (KFunction in constructors) {
             {
                val name = 
                val type = 
                println("name=$name") // name=elements
                println("type=$type") // type=<T>
                for (KTypeProjection in ) {
                    println() // T
                }
            }
        }
    }
}