泛型
认识泛型
定义类、接口、方法时,同时声明了一个或者多个类型变量(如:) ,称为泛型类、泛型接口,泛型方法、它们统称为泛型。
作用:利用泛型,可以限制集合存储数据的类型.
泛型的本质:把具体的数据类型作为参数传给类型变量。
泛型类
类型变量建议用大写的英文字母,常用的有:E、T、K、V 等
public class ArrayList<E>{. . .
}修饰符 class 类名<类型变量,类型变量,…> { }
- 目标:了解泛型类的定义方式
需求:定义一个MyGenericCls类,要求该类有一个属性,属性的类型可以在创建对象时指定
public class MyGenericCls<E>{E name;public void setName(E name) {this.name = name;}public E getName() {return name;}
}
//1.创建对象,将name的类型指定为StringMyGenericCls<String> cls1 = new MyGenericCls<>();cls1.setName("张三");String name1 = cls1.getName();System.out.println(name1);//2.创建对象,将name的类型指定为IntegerMyGenericCls<Integer> cls2 = new MyGenericCls<>();cls2.setName(666);Integer name2 = cls2.getName();System.out.println(name2);//3.泛型类的作用:可以提高一个类中数据类型的灵活性
泛型接口
- 目标:了解泛型接口的定义方式
public interface A<E>{. . .
}
修饰符 interface 接口名<类型变量,类型变量,…> { }
需求:定义一个泛型接口MyGenericInter,并定义实现类实现该接口
public interface MyGenericInter<E> {//接口名后面定义的泛型(类型变量),在整个接口中要使用数据类型的地方都可以用,可以提高一个接口中类型的灵活性void method1(E e);E method2();
}
public class InterImpl1 implements MyGenericInter<String>{@Overridepublic void method1(String s) {}@Overridepublic String method2() {return null;}
}
public class InterImpl2 implements MyGenericInter<Integer>{@Overridepublic void method1(Integer integer) {}@Overridepublic Integer method2() {return null;}
}
泛型方法
- 目标:了解泛型方法的定义方式
public static <T> void test(T t){
}修饰符 <类型变量,类型变量,…> 返回值类型 方法名(形参列表) { }
需求:定义一个泛型方法,可以接收任意类型的引用数据类型数组,将其变成ArrayList集合返回
/*定义方法:数组的类型不确定!需要提高类型的灵活性* 明确参数:数组类型,数组的元素使用泛型变量* 明确返回值:ArrayList集合,集合中存储的元素和数组元素类型保持一致*/public static <T> ArrayList<T> arrToList(T[] arr) {//2.创建ArrayList集合对象ArrayList<T> list = new ArrayList<T>();//3.遍历数组for (int i = 0; i < arr.length; i++) {T data = arr[i];list.add(data);}return list;}
Integer[] arr1 = {11,22,33,44,55};
ArrayList<Integer> list1 = arrTolist(arr1);
System.out.println(list1);String[] arr2 = {"物", "罗"};
ArrayList<Integer> list2 = arrTolist(arr2);
System.out.println(list2);//[11, 22, 33, 44, 55]
//[物, 罗]
泛型通配符
通配符:?
可以在“使用泛型”的时候代表不确定的类型
泛型的上下限:
泛型上限: ? extends Car
: ? 能接收的必须是Car或者其子类 。
泛型下限: ? super Car
: ? 能接收的必须是Car或者其父类。
4. 目标:了解泛型通配符的使用方式
需求:优化sellApple和sellBanana两个方法,变成一个批量销售所有水果的方法
/*** 水果类*/
public class Fruit {
}//苹果类
public class Apple extends Fruit{
}//香蕉类
public class Banana extends Fruit{
}
//创建苹果集合
ArrayList<Apple> apples = new ArrayList<>();
//创建香蕉集合
ArrayList<Banana> bananas = new ArrayList<>();
//public static void sellFruit(ArrayList<?> fruits){//场景:放入集合时,集合中的数据类型不确定,此时使用泛型通配符?,此时?代表一切类型//public static void sellFruit(ArrayList<?> fruits) {//场景:此时还是不确定给泛型变量赋什么类型,依然使用通配符?,不过要限制它的范围,使用通配符的上限//要求:?要么是水果类型,要么是水果的子类类型public static void sellFruit(ArrayList<? extends Fruit> fruits){System.out.println("销售水果");}//批量销售苹果public static void sellApple(ArrayList<Apple> apples) {System.out.println("销售苹果");}//批量销售香蕉public static void sellBanana(ArrayList<Banana> bananas) {System.out.println("销售香蕉");}
}
public static void main(String[] args) {//需求:优化sellApple和sellBanana两个方法,变成一个批量销售所有水果的方法//创建苹果集合ArrayList<Apple> apples = new ArrayList<>();//创建香蕉集合ArrayList<Banana> bananas = new ArrayList<>();//销售苹果和香蕉//sellApple(apples);//sellBanana(bananas);//sellBanana(apples);//sellApple(bananas);//此时方法的形参类型是ArrayList,所以sellFruit、sellApple、sellBanana三个方法的类型是一样的!sellFruit(apples);sellFruit(bananas);//创建狗集合,并销售ArrayList<Dog> dogs = new ArrayList<>();//有些时候,虽然不确定具体是什么类型,但是还是要限制一下类型的范围,此时需要限制类型是水果!//sellFruit(dogs);}