18、泛型
目录
一、为什么需要泛型?
1、在完成以下需求时
(1)在ArrayList中添加3个Dog对象
(2)Dog对象包含name, age, 并输出name和age
//使用传统方法
ArrayList arrayList = new ArrayList();
arrayList.add(new Dog("旺财", 5));
arrayList.add(new Dog("小白", 7));
arrayList.add(new Dog("小黄", 3));
//问题:如果不小心加入了一只猫
arrayList.add(new Cat("yuan", 18));
//遍历
for (Object o: arrayList) {
//向下转型
Dog dog = (Dog) o;
System.out.println(dog.getName() + '-' + dog.getAge());
}
2、用传统方法解决,可能会遇到如下的问题
(1)不能对加入到集合ArrayList中的数据进行约束(不安全)
(2)遍历的时候需要进行类型转换,如果集合中的数据量较大,对效率有影响
3、使用泛型解决
ArrayList<Dog> arrayList = new ArrayList<Dog>();
arrayList.add(new Dog("旺财", 5));
arrayList.add(new Dog("小白", 7));
arrayList.add(new Dog("小黄", 3));
//存入Cat会报错
//arrayList.add(new Cat("yuan", 18));
for (Dog dog : arrayList) {
System.out.println(dog.getName() + "-" + dog.getAge());
}
(1)使用泛型后,表示存入该集合中的元素是Dog类型对象
(2)加入其他类型会报错
(3)在遍历的时候可以直接取出Dog类型而不是Object类型
二、什么是泛型?
1、泛型概述
【可以代表一种数据类型,具体类型由程序员指定】
(1)泛型又称为参数类型,是jdk5.0出现的新特性,解决数据类型的安全性问题
(2)在类声明或实例化时只要指定好需要的具体的类型即可
(3)作用:可以在类声明时通过一个标识标识类中某个属性的类型,或者某个方法的返回值类型,或者是参数类型
2、泛型的语法
(1)泛型的声明
interface 接口<T> {
}
或
class 类<T> {
}
(2)实例化
如:
List<String> strlist = new ArrayList<String> ();
Iyerator<Customer> itertor = customers.iterator();
三、泛型的使用细节
(1)泛型只能是引用类型
(2)给泛型指定具体类型后,可以传入该类型或者其子类类型
(3)不指定类型,泛型默认为Object类
(4)泛型的使用形式
ArrayList<Integer> list1 = new ArrayList<Integer>();
//在实际开发中往往简写,编译器会自动推断
ArrayList<Integer> list1 = new ArrayList<>();
四、自定义泛型
1、泛型类
(1)基本语法
class 类名<T,R,...> {//可以由多个泛型
成员;
}
(2)注意细节
- 普通成员可以使用泛型(属性、方法)
- 使用泛型的数组不能初始化
- 静态方法不能使用类的泛型
- 泛型类的类型,是在创建对象时确定的(因为创建对象时,需要指定确定类型)
- 如果在创建对象时,没有指定类型,默认为Object
2、泛型接口
(1)基本语法
interface 接口名<T, R,...> {
}
(2)注意细节
- 接口中,静态成员也不能使用泛型——(接口中的属性 ,只能是
final
,而且是public static final
修饰) - 泛型接口的类型,在继承接口或者是实现接口时确定
- 没有指定类型,默认为Object
3、泛型方法
(1)基本语法
修饰符<T, R,...> 返回类型 方法名(参数列表) {
方法体;
}
(2)注意细节
- 泛型方法可以定义在普通类中,也可以定义在泛型类中
- 当泛型方法被调用时,类型会确定
//使用了泛型
public void eat(T t) {}//使用了类中定义的泛型
//泛型方法
public<T> void eat(T t) {}//在方法中定义了泛型,也可以使用类定义的泛型
五、泛型的继承和通配符
(1)泛型不具备继承性
//错误,泛型不具备继承性
List<Object> list = new ArrayList<String> ();
(2)通配符
public class GenericExtends {
public static void main(String[] args) {
List<Object> list1 = new ArrayList<>();
List<String> list2 = new ArrayList<>();
List<AA> list3 = new ArrayList<>();
List<BB> list4 = new ArrayList<>();
List<CC> list5 = new ArrayList<>();
printCollection1(list1);
printCollection1(list2);
printCollection1(list3);
printCollection1(list4);
printCollection1(list5);
// printCollection2(list1);//Object,String都没有继承AA
// printCollection2(list2);
printCollection2(list3);
printCollection2(list4);
printCollection2(list5);
printCollection3(list1);
// printCollection3(list2);//String不是CC的父类
printCollection3(list3);
printCollection3(list4);
printCollection3(list5);
}
//接收List类型任何泛型类型的参数
public static void printCollection1(List<?> c) {
for (Object o :
c) {
System.out.println(o);
}
}
//接收List型中继承了AA泛型类型的数据为参数
public static void printCollection2(List<? extends AA> c) {
for (Object o :
c) {
System.out.println(o);
}
}
//接收List类型中泛型类型以CC父类的数据为参数,不限于直接父类
public static void printCollection3(List<? super CC> c) {
for (Object o :
c) {
System.out.println(o);
}
}
}
class AA {
}
class BB extends AA {
}
class CC extends BB {
}