深入理解Java泛型(一)——认识泛型接口和类

文章目录

  • 一、Type接口
  • 二、GenericDeclaration接口
  • 三、Class类
  • 四、Method类
  • 五、Field类
  • 六、ParameterizedType接口
  • 七、TypeVariable接口
  • 八、WildcardType接口
  • 九、GenericArrayType接口

文章内容出自微信公众号:路人甲Java(后面附有原文地址),部分内容自己编写。

工欲善其事必先利其器。本系列分为两篇,此篇带大家了解一些泛型相关的接口和类,下篇为泛型实例。

泛型算是必须要掌握的一块硬核知识,很多地方都会用到,这块如果理解了。在阅读其他框架源码的时候会让你更容易一些。

关于泛型的解析上面,我们需要先了解一些接口和类,这些比较关键,这些都位于java.lang.reflect包中,类图如下:
深入理解Java泛型(一)——认识泛型接口和类_第1张图片
下面一个个解释。

一、Type接口

这是一个顶层接口,java中任何类型都可以用这个来表示,这个接口是Java编程语言中所有类型的公共超接口。这些类型包括原始类型、泛型类型、泛型变量类型、通配符类型、泛型数据类型、数据类型等各种类型。

这个接口源码比较简单,如下:

public interface Type {
    /**
     * Returns a string describing this type, including information
     * about any type parameters.
     *
     * @implSpec The default implementation calls {@code toString}.
     *
     * @return a string describing this type
     * @since 1.8
     */
    default String getTypeName() {
        return toString();
    }
}

这个接口只有一个getTypeName()方法,用于返回具体类型的名称,是一个默认方法,默认会调用当前类的toString方法,实现类也可以对这个方法重写。

二、GenericDeclaration接口

所有声明泛型变量的公共接口,这个接口中定义了一个方法:

public interface GenericDeclaration extends AnnotatedElement {
    /**
     * Returns an array of {@code TypeVariable} objects that
     * represent the type variables declared by the generic
     * declaration represented by this {@code GenericDeclaration}
     * object, in declaration order.  Returns an array of length 0 if
     * the underlying generic declaration declares no type variables.
     *
     * @return an array of {@code TypeVariable} objects that represent
     *     the type variables declared by this generic declaration
     * @throws GenericSignatureFormatError if the generic
     *     signature of this generic declaration does not conform to
     *     the format specified in
     *     The Java™ Virtual Machine Specification
     */
    public TypeVariable[] getTypeParameters();
}

这个方法用于获取声明的泛型变量类型清单

泛型变量可以在类和方法中进行声明,从上面的类图中也可以看出来:Java中任何类可以使用Class对象表示,方法可以使用Method类表示。从类图中还可知:Class类和Method类实现了GenericDeclaration接口,所以可以调用他们的**getTypeParameters()**方法获取其声明的泛型参数列表。

1、类中定义泛型变量类型

public class Demo1

上面代码表示了Demo1这个类中声明了3个泛型变量类型:T1、T2、T3,如果去调用这个类的Class对象中的getTypeParameters方法,可以获取到这三个泛型变量的信息。下篇再为大家实例演示。


2、方法中定义泛型变量类型

public  T3 m1(T1 t1, T2 t2, T3 t3, String s){
	return t3;
}

上面m1方法中声明了三个泛型类型变量:T1、T2、T3;Java中方法的任何信息都可以通过Method对象来获取,Method类实现了GenericDeclaration接口,所以Method类中实现了GenericDeclaration接口中的getTypeParameters方法,调用这个方法就可以获取m1方法中3个泛型变量类型的信息。下篇再为大家实例演示。

三、Class类

这个比较常见(反射机制),Class类的对象表示JVM中一个接口或类,每个Java对象被加载到JVM中都会表现为一个Class类型的对象。Java中数组也被映射为Class对象,所有元素类型相同且维数相同的数组都共享一个Class对象。通过Class对象可以获取接口或类中任何信息,比如:类名、类中声明的泛型信息、类的修饰符、类的父类信息、类的接口信息、类中的任何方法信息、类中任何字段信息等。

1、Class对象获取方式

在程序中,我们可以通过3种方式获取Class对象:

i、  类名.class
ii、 对象.getClass()
iii、Class.forName("类或接口的完整名称/权限定名")

2、常用方法

(1)、Field[] getFields()

这个方法会返回当前类以及其所有父类、父类的父类中所有public类型修饰的字段

	@CallerSensitive
    public Field[] getFields() throws SecurityException {
        checkMemberAccess(Member.PUBLIC, Reflection.getCallerClass(), true);
        return copyFields(privateGetPublicFields(null));
    }

(2)、Field[] getDeclaredFields()

这个方法会返回当前类中所有字段(和修饰符无关),也就是说不管这个字段是public还是private或者是protected,都会返回。有一点需要注意,只返回自己内部定义的字段,不包含其父类中的,这点需要注意,和getFields()是有区别的。

	@CallerSensitive
    public Field[] getDeclaredFields() throws SecurityException {
        checkMemberAccess(Member.DECLARED, Reflection.getCallerClass(), true);
        return copyFields(privateGetDeclaredFields(false));
    }

(3)、Method[] getMethods()

这个方法会返回当前类的以及其所有父类的、父类的父类的、自己实现的接口、父接口继承的接口中的所有public类型的方法,需要注意一下,接口中的方法默认都是public类型的,接口中的方法public修饰符是可以省略的。

    @CallerSensitive
    public Method[] getMethods() throws SecurityException {
        checkMemberAccess(Member.PUBLIC, Reflection.getCallerClass(), true);
        return copyMethods(privateGetPublicMethods());
    }

(4)、Method[] getDeclaredMethods()

返回当前类中定义的所有方法,不管这个方法修饰符是什么类型的,注意只包含自己内部定义的方法,不包含当前类的父类或者其实现的接口中定义的。

    @CallerSensitive
    public Method[] getDeclaredMethods() throws SecurityException {
        checkMemberAccess(Member.DECLARED, Reflection.getCallerClass(), true);
        return copyMethods(privateGetDeclaredMethods(false));
    }

(5)、Type getGenericSuperclass()

返回父类的类型信息,如果父类是泛型类型,会返回超类中泛型的详细信息,这个方法比较关键,后面会有详细案例。

    public Type getGenericSuperclass() {
        ClassRepository info = getGenericInfo();
        if (info == null) {
            return getSuperclass();
        }

        // Historical irregularity:
        // Generic signature marks interfaces with superclass = Object
        // but this API returns null for interfaces
        if (isInterface()) {
            return null;
        }

        return info.getSuperclass();
    }

(6)、TypeVariable>[] getTypeParameters()

Class类继承了java.lang.reflect.GenericDeclaration接口,上面这个方法是在GenericDeclaration接口中定义的,Class类中实现了这个接口,用于返回当前类中声明的泛型变量参数列表

	public TypeVariable>[] getTypeParameters() {
        ClassRepository info = getGenericInfo();
        if (info != null)
            return (TypeVariable>[])info.getTypeParameters();
        else
            return (TypeVariable>[])new TypeVariable[0];
    }

四、Method类

这个类用来表示Java中任何一个方法,通过这个类可以获取Java中方法的任何信息,比如:方法的修饰符、方法名称、方法的参数、方法的返回值、方法中声明的泛型参数列表等方法的一切信息。

常用方法

1、String getName()

用来获取方法的名称。

    @Override
    public String getName() {
        return name;
    }

2、Type[] getGenericParameterTypes()

返回方法的参数信息,如果参数是泛型类型,会返回泛型的详细信息。

    @Override
    public Type[] getGenericParameterTypes() {
        return super.getGenericParameterTypes();
    }

3、Type getGenericReturnType()

返回方法的返回值类型,如果返回值是泛型,会包含泛型的详细信息。

    public Type getGenericReturnType() {
      if (getGenericSignature() != null) {
        return getGenericInfo().getReturnType();
      } else { return getReturnType();}
    }

4、TypeVariable< Method >[] getTypeParameters()

Method类继承了java.lang.reflect.GenericDeclaration接口,上面这个方法是在GenericDeclaration接口中定义的,Method类实现了这个接口,用于返回当前方法中声明的泛型变量参数列表

    @Override
    @SuppressWarnings({"rawtypes", "unchecked"})
    public TypeVariable[] getTypeParameters() {
        if (getGenericSignature() != null)
            return (TypeVariable[])getGenericInfo().getTypeParameters();
        else
            return (TypeVariable[])new TypeVariable[0];
    }

五、Field类

这个类用来表示Java中的字段,通过这个类可以获取Java中字段的任何信息,比如:字段的修饰符、字段名称、字段类型、泛型字段的类型等字段的一切信息。

常用方法

1、String getName()

获取字段的名称。

public String getName() {
	return name;
}

2、Class getType()

获取字段类型所属的Class对象。

    public Class getType() {
        return type;
    }

3、Type getGenericType()

获取字段的类型,如果字段是泛型,则返回泛型类型的详细信息;如果字段不是泛型,和getType返回的结果一样。

    public Type getGenericType() {
        if (getGenericSignature() != null)
            return getGenericInfo().getGenericType();
        else
            return getType();
    }

4、Class getDeclaringClass()

获取这个字段是在哪个类中声明的,也就是当前字段所属的类。

    public Class getDeclaringClass() {
        return clazz;
    }

六、ParameterizedType接口

这个接口表示参数化类型,例如 List< String >、Map< Integer, String >、UserMapper< UserModel >这种带有泛型的类型。

常用方法

这个接口中定义了3个方法,都比较重要,我们一起来看看吧!

1、Type[] getActualTypeArguments()

获取泛型类型中的类型列表,就是<>中包含的参数列表。如:List< String >泛型类型列表只有一个是String;而Map< Integer, String >泛型类型中包含2个类型:Integer和String;UserMapper< UserModel >泛型类型为UserModel,实际上就是<>中间包含的类型列表。

2、Type getRawType()

返回参数化类型中的原始类型。比如:List< String >的原始类型为List;UserMapper< UserModel >原始类型为UserMapper,也就是<>符号前面的部分。

3、Type[] getOwnerType()

返回当前类型所属的类型。例如:存在A< T >类,其中定义了内部类InnerA< I >,则InnerA< I >所属的类型为A< I >,如果是顶层类型则返回null。这种关系比较常见的示例是Map接口与Map.Entry接口,Map接口是Map.Entry接口的所有者。

七、TypeVariable接口

这个接口表示的是泛型变量,例如:List< T >中的T就是类型变量;而class C1{}表示一个类,这个类中定义了3个泛型变量类型,分别是T1、T2和T3,泛型变量在java中使用TypeVariable接口来表示,可以通过这个接口提供的方法获取泛型变量类型的详细信息。

常用方法

1、Type[] getBounds

获取泛型变量的上边界,如果未明确上边界类型是什么,默认为Object。例如:Class Test< K extends Person > 中K的上边界只有一个,即Person;而class Test< T extends List & Interable >中T的上边界有2个,即List和Iterable;class Test< T >中T的上边界为Object。

2、D getGenericDeclaration()

获取声明该泛型变量的原始类型。例如:class Test< K extends Person >中的K为泛型变量,这个泛型变量是Test类定义的时候声明的,说明如果调用getGenericDeclaration方法返回的就是Test对象的Class对象。

还有,方法中也可以定义泛型类型的变量,如果在方法中定义,那么上面这个方法返回的就是定义泛型变量的方法了,返回的就是Method对象。

String getName()

获取在源码中定义时的名字。如:class Test< K extends Person >就是K;class Test1< T > 中就是T。

八、WildcardType接口

表示的是通配符泛型,通配符使用问号(?)表示。例如:? extends Number和 ?super Integer。

常用方法

1、Type[] getUpperBounds()

返回泛型变量的上边界列表。

3、Type[] getLowerBounds()

返回泛型变量的下边界列表。

九、GenericArrayType接口

表示的是数组类型,且数组中的元素是ParameterizedType或TypeVariable。

例如:List< String >[] 或者 T[]

这个接口只有一个方法:Type getGenericComponentType()

这个方法返回数组的组成元素。

上面的内容需要大家多看几遍,多理解多思考。下一篇就写案例,加深对上面内容的理解和应用,信息量比较大,请大家把这篇基础知识打牢哦。

你可能感兴趣的:(Java内核)