美文网首页
Java 泛型之type

Java 泛型之type

作者: PuHJ | 来源:发表于2018-08-31 17:37 被阅读22次

一、泛型的好处

简单的说,

  • 泛型编程,意味着编写的代码可以被很多不同类型的对象所重用。比如ArrayList类使用泛型可以聚合Integer和String,而不是单独编写个ArrayList。有种多态的感觉。
  • 提供错误检查机制,如ArrayList<String> list = new ArrayList<>();list就不可以添加非String类型的变量,java编译器就会错误检测。再者不需要提供强制类型装换,如String s = list.get(0);

二、类型变量命名约定

  • T : 普通的泛型
  • K : Key的简写,用于键值对的键
  • V : Value的简写,用于键值对的值

三、泛型体系

Type体系
(1)、Type接口

官方的解释:Type 是 Java 编程语言中所有类型的公共高级接口。它们包括原始类型、参数化类型、数组类型、类型变量和基本类型。

/**
 * Type is the common superinterface for all types in the Java
 * programming language. These include raw types, parameterized types,
 * array types, type variables and primitive types.
 *
 * @since 1.5
 */
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();
    }
}

从图中可以看出Type的四大子接口,它们分别代表不同的类型:

  • 原始类型(Class) : 对应的就是普通的类,注解等。如String.getClass()就是一个原始类型。
  • 参数化类型(ParameterizedTypes):是整个泛型,如List<T> list;
  • 类型变量(TypeVariable) : 如List<T> list 中的T
  • 数组类型(GenericArrayType) :并不是普通的数组String[] 、byte[],而是带有泛型的数组,即T[]
  • 基本类型 :基本类型,即int,float,double等。
  • 通配符类型(WildcardType):List<?> 带有?的

泛型多是在框架中应用比较多,如Retrofit框架中的源码,该方法的大体意思就像是获取List<String>中的最外层的List类型。

  static Class<?> getRawType(Type type) {
    if (type == null) throw new NullPointerException("type == null");

    if (type instanceof Class<?>) {
      // Type is a normal class.
      return (Class<?>) type;
    }
    if (type instanceof ParameterizedType) {
      ParameterizedType parameterizedType = (ParameterizedType) type;

      // I'm not exactly sure why getRawType() returns Type instead of Class. Neal isn't either but
      // suspects some pathological case related to nested classes exists.
      Type rawType = parameterizedType.getRawType();
      if (!(rawType instanceof Class)) throw new IllegalArgumentException();
      return (Class<?>) rawType;
    }
    if (type instanceof GenericArrayType) {
      Type componentType = ((GenericArrayType) type).getGenericComponentType();
      return Array.newInstance(getRawType(componentType), 0).getClass();
    }
    if (type instanceof TypeVariable) {
      // We could use the variable's bounds, but that won't work if there are multiple. Having a raw
      // type that's more general than necessary is okay.
      return Object.class;
    }
    if (type instanceof WildcardType) {
      return getRawType(((WildcardType) type).getUpperBounds()[0]);
    }

    throw new IllegalArgumentException("Expected a Class, ParameterizedType, or "
          + "GenericArrayType, but <" + type + "> is of type " + type.getClass().getName());
  }
(2)、ParameterizedType接口

ParameterizedType 表示参数化类型,也就是泛型,如 Collection<String>。
如:

  • Map<String, Person> map;
  • Set<String> set1;
  • Class<?> clz;
  • Holder<String> holder;
  • List<String> list;

ParameterizedType 接口提供了三个方法:

  • Type[] getActualTypeArguments();
  • Type getRawType();
  • Type getOwnerType();

前两个方法比较常见,以Map<String, Person> map为例,getActualTypeArguments()获取的是String和Person类型的集合。getRawType()是获取到Map类型。

public class ParameterizedTest<T> {
    
    // map对象
    public Map<T,Integer> map;

    public static void main(String[] args) throws Exception{
        
        // 通过反射解析map对象
        Field field = ParameterizedTest.class.getDeclaredField("map");
        Type type =field.getGenericType();
        // 是ParameterizedType类型
        if (type instanceof ParameterizedType) {
            // 1
            Type[] typeArguments = ((ParameterizedType) type).getActualTypeArguments();
            for (Type t : typeArguments) {
                // 参数是TypeVariable
                if (t instanceof TypeVariable) { // T 是 TypeVariable类型
                    System.out.println("TypeVariable: "+((TypeVariable) t).getName());
                } else if (t instanceof Class<?>) { // Integer是Class<?> 原始类型
                    System.out.println("Class<?>: "+t);
                }
            }
            
            // 2、
            Type rawType = ((ParameterizedType) type).getRawType();
            System.out.println("ParameterizedType: "+rawType);
        }
    }
}
结果:
TypeVariable: T
Class<?>: class java.lang.Integer
ParameterizedType: interface java.util.Map
(3)、TypeVariable接口

类型变量,例如:T、K、V等变量。TypeVariable代表着泛型中的变量,而ParameterizedType则代表整个泛型。
接口方法:

  • Type[] getBounds(); // 得到上限的泛型
  • D getGenericDeclaration(); // 获取声明该类型变量实体(是Class, Constructor, Method)
  • String getName(); // 获取名字
public class TypeVariableTest<T> {

    public static void main(String[] args) {
        // 得到T
        TypeVariable<?>[] typeParameters = TypeVariableTest.class.getTypeParameters();
        for (TypeVariable type : typeParameters) {
            System.out.println(type.getGenericDeclaration());  // 查看是哪里申明的
            System.out.println(type.getName());
            System.out.println();
            
            Type[] boundTypes = type.getBounds();
            for (Type boundType : boundTypes) {
                System.out.println(boundType);
            }
        }
    }
}
结果:
class JavaFinal.TypeVariableTest
T

class java.lang.Object

从D getGenericDeclaration()来看,可以在哪些地方声明泛型T了?
需要了解到GenericDeclaration这个接口,这是个声明泛型的接口


GenericDeclaration继承关系

由结构可以看出,一共有三个地方可以声明泛型。

  • 类 : TypeVariableTest<T>
  • 方法 : <T> void print(T t)
  • 构造方法: public <T> TypeVariableTest()
(4)、GenericArrayType接口

泛型数组。 它的组成元素是ParameterizedType或TypeVariable 类型。
接口方法:

  • Type getGenericComponentType(); // 返回泛型数组中元素的Type类型,即T[] 中的T(TypeVariableImpl)

下列是几个GenericArrayType泛型例子:

// 属于 GenericArrayType
List<String>[] pTypeArray;
// 属于 GenericArrayType
T[] vTypeArray;
// 不属于 GenericArrayType
List<String> list;
// 不属于 GenericArrayType
String[] strings;
// 不属于 GenericArrayType
Person[] ints;

Retrofit中的例子:

    if (type instanceof GenericArrayType) {
      Type componentType = ((GenericArrayType) type).getGenericComponentType();
      return Array.newInstance(getRawType(componentType), 0).getClass();
    }
(5)、WildcardType

通配符泛型。这个一般不太常使用。只是获取通配符的上限泛型处理。

    if (type instanceof WildcardType) {
      return getRawType(((WildcardType) type).getUpperBounds()[0]);
    }

相关文章

  • Java 泛型之type

    一、泛型的好处 简单的说, 泛型编程,意味着编写的代码可以被很多不同类型的对象所重用。比如ArrayList类使用...

  • Java泛型之Type

    1、Type Type是一个接口,是所有类型的父类,下图展示了Type的继承结构: 可以看到Type的子类有如下几...

  • Java泛型: 类型擦除(type erasure)

    type erasure & reified generic Java的泛型不同于C++的模板:Java泛型是"t...

  • Java 泛型Type

    Java中的Type 接口 ParameterizedType 参数化类型 作用于类、参数类型上,如Map , f...

  • java中的类型擦除type erasure

    java中的类型擦除type erasure 简介 泛型是java从JDK 5开始引入的新特性,泛型的引入可以让我...

  • java泛型深度解读

    简介 泛型是Java SE 1.5的新特性,泛型的本质是参数化类型 ( type parameters ),也就是...

  • 不理解Typescript泛型?看完就理解了

    如何理解泛型 泛型(Generic Type)存在于许多编程语言中,许多刚接触Typescript且没有Java、...

  • 泛型

    1. 泛型概述 泛型(Generic type 或者 generics)是对 Java 语言的类型系统的一种扩展,...

  • Type 深入了解

    Type.IsGenericType 返回类型是否是泛型,true泛型, false非泛型 typeof(Type...

  • Java语言中的Type

    Java中的Type 简介 泛型引入之前,Java中的类型系统很简单: 完全取决于Class,泛型引入后,变为以j...

网友评论

      本文标题:Java 泛型之type

      本文链接:https://www.haomeiwen.com/subject/sxtewftx.html