首页 > 其他分享 >泛型

泛型

时间:2022-10-12 18:12:09浏览次数:55  
标签:类型 擦除 泛型 static public Pair

类型参数的好处

  • 程序更已读,可以明显知道代表的什么类型数据
  • 更安全,在存储可以根据类型检查,读取的时候不用强制类型转换

泛型类

public class Pair<T>
{
  private T first;
  private T second;
}
  • 参数类型可以是一个或者多个,用“<>”括起来跟在类名后面
  • 一般使用E表示集合的元素类型,K,V表示键和值的类型,T、U表示任意类型

泛型方法

class ArrayAlg
{
    public static <T> T getMiddle(T...a)
    {
      return a[a.length/2];
    }
}
  • 类型变量放在修饰符的后面,返回类型的前面。
  • 可以在泛型类或者普通类中定义。
  • 调用泛型方法时,可以将具体类型放在尖括号中,放在方法名前面
  • 大多数时候,编译器会根据参数来推断泛型类型,会根据多个参数的的父类往上推,找到共同的父类,如果推导出共同父类不唯一,则会报错

类型变量T的限定

//<T extends BoundingType>

public static <T extends Comparable> T min(T...a)
  • T 和 限定类型BoundingType 可以是类,也可以是接口。限定类型是接口时代表实现了该接口,是类时代表继承了该类。
  • 一个类型变量或通配符可以有多个限定,如: T extends Comparable & Serialzable 用 “&”分隔多个限定
  • 多个限定由最多一个类和多个接口,如果有类时必须放在第一个。 如: T extends Number & Comparable

泛型代码和虚拟机

虚拟机没有泛型类型对象-所有对象都属于普通类,编译过后,类型变量都会被擦除。

类型擦除

  • 无论何时定义一个泛型类型,都会自动提供一个相应的原始类型。这个原始类型的名字就是去掉类型参数后的泛型类型名
// Pair<T>的原始类型如下:
public class Pair(){
  private Object first;
  //........

}
//Pair<String> Pair<Integer> 擦除类型后都是 Pair类型

  • 类型变量会被擦除,并替换为其第一个限定类型(无限定类型则替换成Object)
  • 多个限定类型时,应该将没有方法的标签接口放在最后面

转换泛型表达式

  • 访问泛型方法或者泛型字段时,类型擦除后,返回类型为第一限定类型或者Object,编译器会插入强制类型转换来返回具体类型

转换泛型方法


泛型转换总结

  • 虚拟机中没有泛型,只有普通的类和方法
  • 所有的类型参数T都会转换为他们的限定类型
  • 会合成桥方法来保持多态
  • 为保持类型安全性,必要时会插入强制类型转换

限制与局限性

  1. 不能用基本类型实例化类型参数
    类型擦除后,类型参数为限定类型,不能接口基本类型,可以使用对应的包装类型

  2. 运行时类型查询只适用于原始类型
    虚拟机中的对象都有一个特定的非泛型类型,也就是Class对象。所有泛型类型对象查询只返回擦除后的原始类型
    比如 Pair Pair 的getClass方法返回的都是Pair.class

  3. 不能创建参数化类型的数组,但可以声明,可以使用ArrayList来收集参数化类型队形,更安全,有效

  Pair<String>[] data ;//true
  data = new Pair<String>[10] //Error
  
  ArrayList<Pair<String>> list = new ArrayList<>();//安全、有效
  1. Varagrs可变参数警告
public static <T> void addAll(Collection<T> coll,T...ts)
{
  for(T t:ts) coll.add(t);
}
  • 向可变参数传递泛型类型的实例,虚拟机就会创建一个参数化类型数组,违背了上一条规则,此时规则会放松,会产生一个警告,
    可以通过@SuppressWarning("Unchecked") 或者 @SafeVaragrs 注解来抑制警告
  • @SafeVaragrs注解只能用于 final、static或者(Java9中)private的构造器和方法,也就是不允许被覆盖的方法。
  • 可以使用@SafeVarargs来创建泛型数组
@SafeVarargs static <E> E[] array(E...array) {return array;}

Pair<String> table = array(pair1,pair2);
//这看起来可以创建泛型数组了,不过很危险。
Object[] objarray = table;
objarray[0] = new Pair<Integer>();//可以顺利存储,但是处理table【0】时就会出现异常
  1. 不能实例化类型变量T
//构造方法
public Pair() { first = new T(); second = new T();}//Error,因为T类型会被擦除

//可以通过传递参数类型来实例化
public static <T> Pair<T> makePair<Class<T> cl>
{
  return new Pair<>(cl.getConstructor().newInstance(),cl.getConstructor().newInstance())
}

  1. 不能构造泛型(类型变量T)数组
public static <T> T[] makeArray(T...a)
{
  T[] = new T[2];//Error  不能构造类型变量T数组,会被擦除
}

//通过接收数组构造器表达式来创建泛型数组

public static <T> T[] makeArray(IntFunction<T[]> constr,T...a)
{
  T[] result = constr.apply(2);
...
}

String[] names = makeArray(String[]::new,"aa","bb");

  1. 泛型类的静态上下文中类型变量无效
public class Pair<T>{
  private static T first;// Error

  //Error
  public static T getT(){
    return first;
  }
}

  1. 不能抛出或捕获泛型类的实例
    泛型类不能继承自Throwable,也不能再catch块中捕获类型变量T

  2. 可以取消对检查型异常的检查
    Java异常处理的基本准则是必须为所有检查型异常提供一个处理器。可以利用以下方法取消这个机制

@SuppressWarning("unChecked")
static <T extends Throwable> void throwAs(Throwable t) throws T
{
  throw (T) t;
}
  1. 注意擦除后的冲突
    比如泛型类中定义一个equals方法,类型擦除后与Object中继承的方法冲突
    如果两个接口类型是同一接口的不同参数化,一个类或类型变量就不能同时作为这两个接口类型的子

泛型类型的继承规则

  • Pair 与 Pair 没有关系
  • ArrayList 与 List 是继承关系

通配符类型

标签:类型,擦除,泛型,static,public,Pair
From: https://www.cnblogs.com/studyhaha/p/16772671.html

相关文章

  • java中的泛型总结
    要我直接说出泛型是个what我还真讲不出来,这里先由一道问题引入:定义一个坐标点类,要求能保存各种类型的数据,如:整形,浮点型,和字符串类型既然变量类型起先不确定,那么很容易想到......
  • Golang 泛型使用
    Golang泛型泛型函数定义funcFunc1[Tint|int32|int64|float32|float64](a,bT)T{ returna+b}使用Func1[int32](1,2)但是这样好像看起来很丑,所......
  • 浅谈Go1.18版本新特性——泛型
    泛型Generics:引入了对使用参数化类型的泛型代码的新支持,达到了算法可复用的目的。两数求和,泛型函数的使用假设我们要计算两个数的和,函数可以这样子写funcAdd(a......
  • KTV和泛型(3)
    泛型除了KTV,还有一个让人比较疑惑的玩意,而且它就是用来表达疑惑的:?虽然通过泛型已经达到我们想要的效果了,例如:List<String>list=newArrayList<String>();这样就可以放心......
  • KTV和泛型(1)
    说起KTV恐怕没几个人不知道的。虽然这玩意没有过去那么火热了,但喝了酒之后再去飙几个高八度的爆破音还是蛮爽的。但Java里面也有一个基础特性用到了KTV——泛型。泛型,它的作......
  • KTV和泛型(3)
    泛型除了KTV,还有一个让人比较疑惑的玩意,而且它就是用来表达疑惑的:?虽然通过泛型已经达到我们想要的效果了,例如:List<String>list=newArrayList<String>();这样就可以......
  • KTV和泛型(2)
    很多使用泛型的小伙伴,都会有一个疑惑:为什么有的方法返回值前带<T>、<K,V>之类的标记,而有的方法返回值前又什么都不带呢?就像这样://实体基类classEntity{publicS......
  • C#委托之一例看懂泛型委托
    以为委托在编程中频繁使用,所以微软为使开发者方便使用委托,省去繁琐的重复定义。给我们提供了三种定义好的泛型委托,分别是Action、Func和Predicate。下面分别介绍Action:......
  • Java 一个List泛型根据另一个List泛型的属性进行过滤
    这个需求是在批量入库的时候,进行批量校验用到的1.逻辑是传入List参数,需要入库2.根据List去查询库中是否存在3.用传入的List进行过滤,获取苦衷不存在的resList4.插入resLi......
  • 【Java基础】泛型概述、泛型方法、泛型接口、类型通配符及可变参数的使用
    目录​​一、泛型概述和好处​​​​二、泛型类​​​​三、泛型方法​​​​四、泛型接口​​​​五、类型通配符​​​​六、可变参数​​​​可变参数的使用​​一、泛型......