泛型
泛型就是可以接受数据类型的数据类型
- 泛型是参数化类型,用来解决数据类型的安全性问题
- 在类声明或者实例化的时候只要指定好具体的类型即可
- 泛型保证了程序在没有编译警告的时候,就不会出现 ClassCastException
泛型的作用,就是在类声明的时候通过一个标记表示类中某个属性的类型,或者是某个方法的参数 / 返回值类型
如:
class Person<E> { // 声明泛型
E s; // 声明泛型类型的参数
public Person(E s){
this.s = s;
}
public E fun() {
return this.s;
}
}
如果初始化的时候,有语句:Person<String> p = new Person<String>("456");
那么刚刚的类就可以理解为:
class Person { // 声明泛型
String s; // 声明泛型类型的参数
public Person(String s){
this.s = s;
}
public String fun() {
return this.s;
}
}
泛型声明
interface<T> {}
class<K, V> {}
其中, T、K、V 不代表值,而是表示类型。这里用任意字母都可以
泛型使用
List<Integer> list = new ArrayList<>();
List<Integer> list2 = new ArrayList<Integer>(); // 简写
// List<int> list = new ArrayList<>(); // 不能使用基本类型
- 在指定泛型具体类型后,可以传入该类对象,或者子类对象
- 如果不指定泛型类型,那么默认就是 Object
自定义泛型
注意
- 普通成员(属性、方法)可以使用泛型,静态成员不可以使用
- 使用泛型的数组不能初始化
- 静态方法中不能使用类的泛型
- 泛型类的类型,在创建对象的时候确认(创建的时候需要指定)
- 泛型接口的类型,在继承或者实现的时候指定。由于接口的属性都属于静态类型,所以接口中不可以定义泛型属性
- 创建对象时未指定,默认 Object
例子:
// T R M 是泛型标识符
class Tiger<T, R, M> {
String name;
// 普通成员属性可以使用泛型
R r;
M m;
T t;
// 泛型数组不能初始化,因为数组 new 的时候无法确定 T 的类型,就无法在内存开辟空间
// T[] arr = new T[5];
T[] arr; // 可以定义
// 静态属性不能使用泛型,因为静态属性是在类加载的时候创建的,此时对象并未创建
// 也就是此时没有指定类型,那么静态属性也就无法确定自身的类型,不能创建
// static R r2;
public Tiger(String name, R r, M m, T t) {
this.name = name;
this.r = r;
this.m = m;
this.t = t;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
// 普通方法使用泛型
public R getR() {
return r;
}
public void setR(R r) {
this.r = r;
}
public M getM() {
return m;
}
public void setM(M m) {
this.m = m;
}
public T getT() {
return t;
}
public void setT(T t) {
this.t = t;
}
}
自定义泛型方法
语法:
修饰符 <T, R, …>返回类型 方法名(参数列表){}
例子:
// 例子
class Car{
public <T, R>void func(T t, R r){ // 泛型方法
System.out.println(t.getClass());
System.out.println(r.getClass());
}
}
// 调用
public static void main(String[] args) {
Car car = new Car();
car.func(300, "666"); // 泛型会自动装箱成对应的类型
car.func("6666", 666); // 泛型会自动装箱成对应的类型
}
注意:
- 泛型方法可以定义在泛型类中,也可以定义在普通类中
- 泛型方法被调用时,类型会确定
public void eat(E e) {}
这种不是泛型方法,因为修饰符后没有 <T, R…>,这是使用了泛型,一般是使用类声明的泛型- 泛型方法可以使用类声明的泛型(泛型方法的泛型标识符与类的一致),也可以自己声明(泛型方法的泛型标识符与类的不一致)
泛型的继承和通配符
- 泛型不具备继承性
List<Object> list = new ArrayList<String>(); // 是错误的
- <?> :支持任意泛型类型
- <? extends A> :支持 A类及其子类,规定了泛型的上限
- <? super A> :支持 A类及其父类,规定了泛型的下限
例子:
public class CustomGenericTest01 {
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<>();
// 都可以执行
print(list1);
print(list2);
print(list3);
print(list4);
print(list5);
// extendsTest(list1); 不可以执行,非 AA及其子类
// extendsTest(list2); 不可以执行,非 AA及其子类
extendsTest(list3);
extendsTest(list4);
extendsTest(list5);
superTest(list1);
// superTest(list2); 不可以执行,非 AA及其父类
superTest(list3);
// superTest(list4); 不可以执行,非 AA及其父类
// superTest(list5); 不可以执行,非 AA及其父类
}
public static void print(List<?> list) {
for (int i = 0; i < list.size(); i++) {
System.out.println(list.get(i));
}
}
public static void extendsTest(List<? extends AA> list) {
System.out.println("666");
}
public static void superTest(List<? super AA> list) {
System.out.println("7777777");
}
}
class AA {
}
class BB extends AA{
}
class CC extends BB {
}