10. 泛 型
10.1泛型
JDK5新增的特性
**概念:**允许在定义类、接口时通过一个标识表示类中某个属性的类型或是某个方法的返回值及参数类型,在继承或实现这个接口、用此类型声明变量、创建对象时确定
- JDK1.5为集合框架中的接口和类增加了泛型支持,从而可以在声明集合、创建集合对象时传入类型实参
使用泛型目的:
- 解决元素存储的安全性问题
- 解决获取数据元素时,需要类型强转的问题
泛型原理: 泛型,JDK1.5新加入的,主要原理是在类声明时通过一个标识表示类中某个属性的类型或者是某个方法的返回值及参数类型。这样在类声明或实例化时只要指定好需要的具体的类型即可
** Java泛型可以保证如果程序在编译时没有发出警告,运行时就不会产生ClassCastException异常。同时,代码更加简洁、健壮**
10.2 使用泛型
泛型的声明:
**泛型的实例化:**一定要在类名后指定类型参数的值(类型)
泛型的使用场景:
- 在集合中使用泛型
- 自定义泛型类、接口
- 泛型方法
- 泛型接口
1. 在集合中使用泛型
- 集合接口和集合类在JDK 5.0时都修改为带泛型的结构
- 在实例化集合类时,可以指明具体的泛型类型
- 在集合类或接口中定义类或接口时,内部结构(方法、构造器、属性等)使用到类的泛型的位置,都指定为实例化的泛型类型
- 泛型的类型必须是类,如果要用基本数据类型,需要用其对应的包装类
- 如果实例化没有指明其类型,默认为Object类型
- JDK7新特性:类型推断---->根据引用变量的类型参数判断对象的类型参数
2.自定义泛型类、接口
-
泛型类可能有多个参数,应将多个参数一起放在尖括号中
-
泛型类的构造器不声明泛型
-
实例化后,操作原来泛型位置的类型必须和指定的泛型一致
-
泛型不同的引用不能相互赋值
-
泛型如果不确定,将被擦除,即按照Object来处理,但不等价于Object;经验:泛型使用一路都用,要不用,一路都不要用
-
如果泛型结构是一个接口或抽象类,则不可创建泛型类的对象
-
JDK 1.7 泛型简化操作,类型推断
-
泛型的指定中不能使用基本数据类型,了已使用包装类替换
-
类声明了泛型,类的内部结构就可以使用类的泛型,可以作为非静态属性的类型、非静态方法的参数类型、非静态方法的返回值类型;但在静态方法中不能使用类的泛型
-
异常类不能泛型
-
不能new泛型数组(new E[]),但是可以(E[] elements = (E[]) new Object[capacity]);
-
父类有泛型,子类可以选择保留泛型也可以选择指定泛型类型
- 子类不保留父类泛型:
- 没有类型-----擦除
- 指定自己的新增泛型
- 子类保留父类泛型:
- 全部保留-----和父类泛型相同
- 部分保留-----保留一部分
- 子类不保留父类泛型:
-
如果定义了泛型类,实例化没有指明类的类型,则认为此泛型类型为Object类型
-
如果定义了类时带泛型的,建议在实例化时要指明类的泛型
**3.泛型方法:**在方法中出现了泛型的结构,泛型参数与类的泛型参数没有任何关系;泛型方法可以声明为静态的,因为泛型参数是在调用方法时确定的,并非在实例化类时确定
- 在方法的返回值类型左面 <泛型类型参数>
- 只有在调用方法时只能通过实参来确定泛型类型,一旦有反省类型作为参数,只有在调用时才能真的确定
- 非静态方法中要使用泛型,它所属的类如果也有泛型,在使用时创建对象必须泛型化
10.3 对于泛型类
1. 对象实例化时不指定泛型,默认为Object
2. 泛型不同的引用不能相互赋值
3. 加入集合中的对象类型必须与指定的泛型类型一致
4. 静态方法中不能使用类的泛型
5. 如果泛型类是一个接口或抽象类,则不可创建泛型类的对象
6. 不能在catch中使用泛型
7. 从泛型类派生子类,泛型类型可以具体化
10.4 泛型和继承的关系
- B类继承了A类,但是泛型并不具备子父类关系,G和G两者是并列关系
- 子类在继承泛型的时候可以写死泛型
- 子类在继承泛型时可以继续保持父类的泛型
10.5 泛型和多态的关系
- 泛型不支持多态性
10.6 通配符
使用:
- 类A是类B的父类,G和G两者是并列关系,二者共同的父类是G<?>
List<?> 可以读取,写入时只能写入null
List<? extends Number> (无穷小 , Number]只允许泛型为Number及Number子类的引用调用,用来遍历
List<? super Number> [Number , 无穷大)只允许泛型为Number及Number父类的引用调用,可以添加Number的子类元素
List<? extends Comparable> 只允许泛型为实现Comparable接口的实现类的引用调用