广西网站建设运营费用,重庆建设网站公司,可以自己做logo的网站,wordpress收款生成源码目录
泛型
1. 什么是泛型
2.泛型方法
3.通配符上界#xff08;泛型的协变#xff09;
4.通配符下界#xff08;泛型的逆变#xff09;
5.泛型的编译#xff08;擦除机制#xff09; 泛型 泛型#xff1a;就是让一个类能适用于多个类型#xff0c;就是在封装数据结…目录
泛型
1. 什么是泛型
2.泛型方法
3.通配符上界泛型的协变
4.通配符下界泛型的逆变
5.泛型的编译擦除机制 泛型 泛型就是让一个类能适用于多个类型就是在封装数据结构时能让封装的类型被各种类型使用所以引入了泛型的概念虽然有了泛型什么数据都可以放但是更多情况下我们还是希望他只能持有一种数据类型。所以泛型的主要目的指定当前的容器要持有什么类型的对象让编译器去做检查。 1. 什么是泛型
语法格式如下 泛型类类型实参变量名;//定义一个泛型类引用 new 泛型类类型实参(构造方法实参);//实例化一个泛型类对象 一般用T作为占位符 表示当前类是一个泛型类。Java中的泛型参数只能是引用类型不能是基本类型这与Java的泛型擦出机制有关。 实例
MyArrayInteger list new MyArrayInteger();
*裸类型Raw Type 这是一个泛型类但没有带着类型实参
MyArray list new MyArray();
裸类型是为了兼容老版本的API保留机制我们不要轻易使用。
2.泛型方法 泛型方法定义一个泛型方法我们需要在方法返回值前使用尖括号声明一个或多个泛型参数然在方法中就可以用到声明的泛型参数了调用泛型方法时我们不需要手动写出类型编译器会根据你的调用自动推导出具体类型。
静态泛型方法泛型类有一个局限静态方法和静态属性访问不了类上定义的泛型参数静态泛型方法的定义和使用与普通泛型方法一致。 泛型类和泛型方法的使用场景 当泛型参数需要在多个方法或成员属性间扭转就使用泛型类比如集合。 当泛型参数只需要作用于某个方法那就使用泛型方法。 3.通配符上界泛型的协变
泛型类型是具有不变性的比如下面代码就是错误的
ArraylistObject objectList;
ArrayListString stringList new ArrayList();
objectListstringList//这里会报错objectList.add(new Shit());
String str stringList.get(0);
//因为我们无法将一个object对象转化为string对象所以在编译层面上面的赋值就会直接报错 为了让泛型变得更灵活Java引入了通配符?通过下面的代码来给大家介绍一下通配符的作用
在不使用通配符时因为泛型的不变性下面这段代码会出现问题就使代码非常不灵活。
public static double sum(ListNumber list){double result 0;for(Number number : list){result number.doubleValue();}return result;
}ListDouble doubleList new ArrayList();
sum(doubleList)//这里会报错
我们可以使用通配符上界?:extends T来使代码更灵活
public static double sum(List? extends Number list){double result 0;for(Number number : list){result number.doubleValue();}return result;
}ListDouble doubleList new ArrayList();
sum(doubleList)
这种写法也被叫做泛型的协变 。
4.通配符下界泛型的逆变
我们还可以使用通配符下界?:super T来使代码变得灵活代码实例如下
class Food {
}
class Fruit extends Food {
}
class Apple extends Fruit {
}
class PlateT {
private T plate ;
public T getPlate() {
return plate;
}
public void setPlate(T plate) {
this.plate plate;
}
}
public class TestDemo {
public static void main(String[] args) {
PlateFruit plate1 new Plate();
plate1.setPlate(new Fruit());
fun(plate1);
PlateFood plate2 new Plate();
plate2.setPlate(new Food());
fun(plate2);
}
public static void fun(Plate? super Fruit temp){
// 此时可以修改添加的是Fruit 或者Fruit的子类
temp.setPlate(new Apple());//这个是Fruit的子类
temp.setPlate(new Fruit());//这个是Fruit的本身
//Fruit fruit temp.getPlate(); 不能接收这里无法确定是哪个父类
System.out.println(temp.getPlate());//只能直接输出
}
}
通配符的优缺点 协变放宽了对子类类型的泛型约束但是缺点是不能对调用的参数进行写入数据只能进行读取数据。 逆变放宽了对父类类型的泛型约束但是缺点是不能对参数进行读取数据只能写入数据。 5.泛型的编译擦除机制
擦除机制的实质就是在编译阶段Java的泛型类型可能是ArrayListInteger但是在java文件编译成字节码的过程中泛型参数部分就被擦出了泛型类泛型方法的参数全部被替换成它的第一个上界或者顶级父类Object在class文件中无论参数是什么JVM实际执行的代码类型其实是ArrayListObject类型这也就引出了很多问题如下
泛型参数只能是引用类型而不能是基本数据类型因为基本数据类型无法被擦除成Object。不能使用instanceof关键字进行泛型类型检测因为在运行时所以的泛型类型都是裸类型。泛型类型无法实例化类型参数T anew T()因为在运行时无法确定T的具体类型也不知道T是否存在无参构造器。无法实例化泛型数组T[] arry new T[2];因为泛型最后都被擦除成Object数组在使用时很容易发生类型转化异常比如object转化不成string。
擦除机制是Java为了引入泛型这个语法而不得不做出的妥协之举泛型语法是JDK5之后引入的为了兼容老版本不得不在编译阶段将泛型擦除成裸类型。但是在其他语言中泛型的使用会非常自然且简单安全在编写代码是我们要了解泛型擦除机制否则可能会引发很多不必要的异常。
类型擦除是指在运行时对于JVM而言泛型参数被擦除掉了并不代表泛型信息消失了才class文件中泛型信息被以其他方式进行保存我们依然可以在运行时通过反射的手段进行泛型类型检测。