Java中泛型Type 解析

1 篇文章 0 订阅

前言

java的反射类型分打开5种类型,如下所示

1.ParameterizedType(参数化类型)
2.GenericArrayType(数组类型)
3.TypeVariable(类型变量)
4.Class(原始类型)
5.WildcardType(通配符类型)

一、ParameterizedType

ParameterizedType表示参数化类型,也就是泛型,例如List,Map等类作为参数的类型。

代码如下(示例):

class TestType {
    val test :List<String> = arrayListOf()
    companion object {
        @JvmStatic
        fun main(args: Array<String>) {
            val declaredField = TestType::class.java.getDeclaredField("test")
            val genericType = declaredField.genericType
            //sun.reflect.generics.reflectiveObjects.ParameterizedTypeImpl
            print(genericType::class.java.name+"\n")
            //java.util.List<java.lang.String>
            print(genericType)
        }
    }
}

打印日志可以看出 genericType 的类型为 ParameterizedType
ParameterizedType 有3个方法可以获取到具体类型
getActualTypeArguments()getRawType()getOwnerType()

getActualTypeArguments
获取泛型中的实际类型,可能会存在多个泛型,例如Map<K,V>,所以会返回Type[]数组,接下面的代码如下

(genericType as ParameterizedType).let {
	val actualTypeArguments = it.actualTypeArguments
    repeat(actualTypeArguments.size){
    	//class java.lang.String
        print(actualTypeArguments[it])
    }
}

可以看出 getActualTypeArguments 是获取泛型的类型。

getRawType
获取声明泛型的类或者接口,也就是泛型中<>前面的那个值

(genericType as ParameterizedType).let {
	val rawType = it.rawType
    //interface java.util.List
    print(rawType)
}

可以看出打印出来的为List类型,也就是泛型<>前面的值。

getOwnerType
此方法是获取泛型的拥有者,那么拥有者是个什么意思?
拥有者”表示的含义–内部类的“父类”,如Map 就是 Map.Entry的拥有者。当没有的时候,会返回 null

(genericType as ParameterizedType).let {
	val rawType = it.rawType
    //null
    print(rawType)   
}

2.GenericArrayType

泛型数组类型,例如E[] 、T[]、List[] (可以理解为包含泛型变量的数组)获取到的type的就是 GenericArrayType
注意:list[] 、String[]不是该类型,他们不包含泛型,他们直接是特殊的Class类型(Class类型在后面讲到)

class TestType {
    val list :Array<List<String>> = arrayOf()
    companion object {
        @JvmStatic
        fun main(args: Array<String>) {
            val declaredField =TestType::class.java.getDeclaredField("list")
            val genericType = declaredField.genericType
            //sun.reflect.generics.reflectiveObjects.GenericArrayTypeImpl
            print(genericType::class.java.name+"\n")
            //java.util.List<java.lang.String>[]
            print(genericType.toString()+"\n")
        }
   }
}

可以看到这时候拿到的genericType 类型为 GenericArrayTypeImpl
该类只包含一个方法,就是 getGenericComponentType

getGenericComponentType
该方法返回脱离数组的类型,即只会脱去最右边的[],返回剩下的值;
例如List[][] 会返回 List[]

(genericType as? GenericArrayType)?.let {
	val genericComponentType = it.genericComponentType
    //java.util.List<java.lang.String>
    print(genericComponentType)
}

可以看到会返回 List<java.lang.String>

3.TypeVariable

泛型的类型变量,指的是List、Map中的T,K,V等值 或者类实现了泛型,对应的变量指明了类的对象,实际的Java类型是TypeVariableImpl(TypeVariable的子类);此外,还可以对类型变量加上extend限定,这样会有类型变量对应的上限;

class TestType<T : Number,Serializable>{
    val data : T? = null
    companion object {
        @JvmStatic
        fun main(args: Array<String>) {
            val declaredField = TestType::class.java.getDeclaredField("data")
            val genericType = declaredField.genericType
            //sun.reflect.generics.reflectiveObjects.TypeVariableImpl
            print(genericType::class.java.name+"\n")
            //T
            print(genericType.toString()+"\n")
        }
    }
}

可以看到这时候返回了 TypeVariableImpl 类型。TypeVariableImpl 也包含了3个方法。getBounds()、getGenericDeclaration()、getName()

getBounds
该方法获取该泛型的上限,也就是泛型类中extend右边的值。如果没有显式限制,那默认是Object

(genericType as? TypeVariable<*>)?.let {
	val bounds = it.bounds
    //class java.lang.Number
    repeat(bounds.size){
    	print(bounds[it].toString() + "\n")
    }
}

可以看到bounds是一个数组,是因为限制是可以多限制(java通过 &符号相连接),所以会返回一个数组

getGenericDeclaration
获取声明该类型变量实体,也就是TestType中的TestType;意思 返回该变量所在的类

(genericType as? TypeVariable<*>)?.let {
	val genericDeclaration = it.genericDeclaration
    //class com.ming.algorithm.test.TestType
    print(genericDeclaration)
}

因为该变量在 TestType 中声明,所以返回了class com.ming.algorithm.test.TestType

getName
获取类型变量在源码中定义的名称;即泛型的名称

(genericType as? TypeVariable<*>)?.let {
	val name = it.name
    //T
    print(name)
}

因为该变量在类中是以 T 声明,所以返回是 T

4.Class

Class 是Type接口的实现类,是我们工作中常用到的一个对象,也就是普通属性的命名

class TestType<T : Number,Serializable>{
    val data : String? = null
    companion object {
        @JvmStatic
        fun main(args: Array<String>) {
            val declaredField = TestType::class.java.getDeclaredField("data")
            val genericType = declaredField.genericType
            //java.lang.Class
            print(genericType::class.java.name+"\n")
            //class java.lang.String
            print(genericType.toString()+"\n")
        }
    }
}

可以看到平常命名的属性 返回的 Type 就是 java.lang.Class

5.WildcardType

?—通配符表达式,表示通配符泛型,但是WildcardType并不属于Java-Type中的一钟, 获取到的 type 依然是 ParameterizedTypeImpl ;例如:java写法 List extends Number>List super Integer>, kotlin 写法 out in 写法。也就是可读可放的关系。
具体可参考:https://blog.csdn.net/u011288271/article/details/107318507 该文章。

class TestType<T : Number,Serializable>{
    val data : List<out String>? = null
    companion object {
        @JvmStatic
        fun main(args: Array<String>) {
            val declaredField = TestType::class.java.getDeclaredField("data")
            val genericType = declaredField.genericType
            //sun.reflect.generics.reflectiveObjects.ParameterizedTypeImpl
            print(genericType::class.java.name+"\n")
            //java.util.List<java.lang.String>
            print(genericType.toString()+"\n")
        }
    }
}

可以看到获取到的类型为 ParameterizedTypeImpl,我们可以通过 actualTypeArguments 继续获取该参数。得到该参数的class 为 WildcardType

(genericType as? ParameterizedType)?.let {
	val actualTypeArguments = it.actualTypeArguments
    //class java.lang.Number
    repeat(actualTypeArguments.size){
    	print(actualTypeArguments[it]::class.java.toString() + "\n")
    }
}

wildcardType 包含2个方法。getUpperBounds()、getLowerBounds();

getUpperBounds
获取泛型变量的上边界(extends),kotlin(in)

getLowerBounds
获取泛型变量的上边界(super),kotlin(out)

注意要点

泛型只能作用于类(Class)构造方法(Constructor),和方法(Method)。 因为 GenericDeclaration;含义为:声明类型变量的所有实体的公共接口;也就是说该接口定义了哪些地方可以定义类型变量(泛型),如上面所示。
GenericDeclaration 继承图
所以 Field 中并没有声明泛型,而是在使用泛型而已,需要在类或者方法有泛型,才可以使用。


总结

以上就是对于泛型不同使用,解析获取实际Class的解析。实际按照要求进行解析。封装好的方法有,如Gson的 G s o n Gson GsonTypes.canonicalize
G s o n Gson GsonTypes.getRawType(type)。 可以直接使用便可以获取到真实的class

  • 17
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值