第九章 泛型

泛型背景

  • Java集合会忘记元素的数据类型,再次取出对象时编译类型会变成Object
  • 集合对元素类型没有限制,可能会导致异常,丢失了对象的状态信息,取出后需要强制类型转换
  • Java5引入参数化类型的概念,允许程序在创建集合时指定集合元素的泪洗过,这种参数化类型被成为泛型,使集合记住元素的类型
  • Java7允许构造器后不需要带完整的泛型信息Map scores = new HashMap<>();菱形语法

泛型类、接口

  • 泛型就是允许在定义类、接口、方法时使用类型形参,这个类型形参在声明变量、创建对象、调用方法时动态指定
  • 任何类、接口都可以增加泛型声明,加了泛型声明的类在创建对象时传入一个类型实参,看起来是生成了无数多个逻辑上的子类,但并不存在
  • 创建带泛型声明的类时,构造器名还是原来的类名,不要增加泛型声明
  • 实现或继承带有泛型声明的接口和类时,使用接口和类时不能包含类型形参,必须传入实际类型或不传入实际类型不带泛型声明,后者会有警告
public class A extends Apple{}//错
public class A extends Apple{}//对
public class A extends Apple{}//对
  • 从传入实际类型的类派生子类需要替换所有类型形参为实际类型,当需要调用父类方法时,要重写父类方法,替换所有类型形参
  • 不存在泛型类,不管为泛型传入哪一种类型实参,都会当成同一个类处理,在内存中只占用一块内存空间
  • 静态方法、静态初始化块、静态变量的声明和初始化中不允许使用类型形参,instanceof运算符后也不能使用泛型类因为不是真正的类

类型通配符

  • 如果F使B的子类型,G是具有泛型声明的类或接口,G不是G的子类型,不允许G对象赋值给G变量
  • List表示它是各种泛型List的父类,并不能把元素加入到其中因为不能确定集合中元素的类型,add()有类型参数作为集合元素类型,所以传给add()的参数必须是其对象或其子类的对象,但不能确定是什么类型
  • get()返回一个未知类型但总是一个Object,可以赋值给Object类型的变量
  • 只希望代表某一类泛型的父类可以设定类型通配符的上限List
  • 同样可以设定类型形参的上限public class Apple,Apple类的类型形参T传入的实际类型参数只能是Number或Number的子类,多个上限(至多一个父类继承上限,可以有多个接口实现上限)public class Apple
  • 给类型形参设置多个上限时接口要位于类上限之后

泛型方法

  • Java5提供了对泛型方法的支持,static void f (T[] a, Collection c)
  • 调用泛型方法时无需显式传入实际类型参数,编译器能根据方法实参推断类型参数,但是不能不顾及类型地乱传参数,会编译错误
  • 大多情况下都可以使用泛型方法来代替类型通配符
  • 当类型形参只使用了一次,且唯一效果是在不同的调用点传入不同的实际类型,此时应该使用通配符。
  • 如果泛型方法的类型形参没有表示一个或多个参数之间的类型依赖关系或方法返回值与参数之间的依赖关系,就不该使用泛型方法
  • 允许在构造方法的签名中声明类型形参,产生所谓泛型构造器
  • 定义泛型构造器后,就可以显式地为构造器中的类型形参指定实际类型
public  f(T t){}//泛型构造器
...
new f("aaa");//隐式指定类型参数的实际类型
new f("aaa");//显示指定类型参数的实际类型
  • 如果程序显式指定了类型形参的实际类型,则不可用菱形语法
new f<>(5);  //正确
new f("aaa");  //正确
new f<>("aaa");  //编译错误
  • 通配符下限,这个通配符表示是T本身或是T的父类
  • public static void copy(Collectiondest, Collection src){...}
    public static void copy(Collectiondest, Collection src){...}同时定义不会发生错误,但是copy(dest, src);调用时会发生编译错误,编译器无法确定调用哪个copy()方法
  • Java8改进类型推断,可以通过返回值和参数推断类型参数的实际类型
  • 但是泛型推断不是万能的有些还是推断不出

擦除和转换

  • 如果没有为泛型类指定实际的类型参数,则把该类型参数称作raw tyoe原始类型,默认时声明该类型参数时制定的第一个上限类型
  • 把一个具有泛型信息的对象赋值给一个没有泛型信息的变量时,泛型信息会被擦出。对于集合,检查类型全部变成类型参数的上限。
  • 可以把Xxx对象直接赋值给一个Xxx变量,编译器仅提示未经检查的转换,但是当把变量集合中的元素当作Xxx取出时会运行异常

泛型与数组

  • 数组元素的类型不能包含类型变量或类型形参,除非是无上限的类型通配符,但可以声明元素类型包含类型变量或类型形参的数组
  • 可以将正常数组对象赋值给泛型数组声明变量,会出现编译警告,完全可能再出现异常
  • 允许创建无上限的通配符泛型数组,此时再强制类型转换时需要用instanceof运算符保证数据类型,但是哟与类型变量再运行时并不存在,无法确定实际类型,所以编译器会再报错

你可能感兴趣的:(第九章 泛型)