之前有接触过泛型也有了解过今天再次看了一下还是有很多收获的。我个人大致做一下总结:
1.泛型本质其实就是参数化类型或者说是类型参数。泛型作为参数和我们方法的实际类型参数的区别就是它是形式类型参数,也就是说它只是泛指我们的类型参数,而不是说具体的某一个类型。为什么需要泛型呢?
List list=new ArrayList<>(); list.add("aa");//添加一个字符串 list.add(2); //使用泛型 List<String> list2=new ArrayList<String>(); list2.add("ddd"); //The method add(int, String) in the type List<String> //is not applicable for the arguments (int //list2.add(3); //这里就报错了 也就是不能往集合中添加任何非String类型的对象 Object object=list.get(0); //没有泛型jvm不知道存储的类型所以获得的就是Object类型 String string=list2.get(0); //通过泛型声明JVM知道我们此集合中 //存储的都是String类型所以不需要做任何处理或者是转换 1,类型安全。 泛型的主要目标是提高 Java 程序的类型安全。通过知道使用泛型定义的变量的类型限制, 编译器可以在一个高得多的程度上验证类型假设。没有泛型,这些假设就只存在于程序员的头脑中 (或者如果幸运的话,还存在于代码注释中)。 2,消除强制类型转换。 泛型的一个附带好处是,消除源代码中的许多强制类型转换。这使得代码更加可读, 并且减少了出错机会。 3,潜在的性能收益。 泛型为较大的优化带来可能。在泛型的初始实现中,编译器将强制类型转换(没有泛型的话, 程序员会指定这些强制类型转换)插入生成的字节码中。但是更多类型信息可用于编译器这一事实, 为未来版本的 JVM 的优化带来可能。由于泛型的实现方式,支持泛型(几乎)不需要 JVM 或类文件更改。 所有工作都在编译器中完成,编译器生成类似于没有泛型(和强制类型转换)时所写的代码, 只是更能确保类型安全而已。
2.泛型的声明主要有一下几种,<T> (泛型一般用大写字幕来表示用<>括号来声明这里是泛型)<?> 、<? extends Animal> 、<? super Animal>(这是为了方便理解Animal是Cat 和Dog的父类)
3.泛型主要用在创建类型参数的类、方法和接口中。
1)创建带有泛型的类:
注意泛型声明的位置是在类名之后的
package me;
public class GeneTest<T> {
private T date;
public T getDate() {
return date;
}
public void setDate(T date) {
this.date = date;
}
}
2)创建带有泛型的方法:
注意声明泛型的位置是在修饰符之后,返回值之前的。
public <T> Class getType(T t){
return t.getClass();
}
3)创建带有泛型的接口:
注意泛型声明的位置是在接口名之后的
public interface Service<T>{
public void get(T t);
}
4.那么我们如何来对带有类型参数的对象赋值呢?首先我们来看一段代码:
//这是是创建了一个带类型参数的链表
List<Animal> list=new ArrayList<Animal>();
List<Cat> list2=new ArrayList<Cat>();
//cannot convert from List<Cat> to List<Animal>
list=list2;
为什么list=list2会报错呢?虽然Animal是Cat的父类但是List<Animal>却不是List<Cat>的父类所以不能这样赋值,这样会破坏数据的完整性。
5.接下来说一说通配符
无限通配符<?>
上限通配符<? extends Animal>
下限通配符<? super Animal>
为什么要使用通配符呢?通配符的作用就是不确定类型或者说容器中存放的不是一种类型时使用的。
但是值得一提的是:在Java集合框架中,对于参数值是未知类型的容器类,只能读取其中元素,不能像其中添加元素, 因为,其类型是未知,所以编译器无法识别添加元素的类型和容器的类型是否兼容,唯一的例外是null
所以List<?>和List<? extends Animal>是不能往里面添加元素的。而List<? super Animal>是可以的。那这是为什么呢?接下来说说我个人的理解:
1)首先List<?>通配符?是匹配任何类型,则其参数类型一定不确定,所以这里的List<?>是肯定不能添加任何元素的。
那为什么List<? extends Animal>容器也不能添加任何元素?
2)<? extends Animal>是上限通配符意思就是此参数类型可以是Animal或者Animal的任何子类。接下来看一个代码帮助理解:
public void add(List<? extends Animal> list){
list.add(new Cat("a", 12));
list.add(new Dog("a",24));
}
//调用方法
add(new ArrayList<Cat>);
这段代码编译是不通过的。那么此时为什么报错?显而易见我传过来的参数
new ArrayList<Cat>只能存储猫类不能存储Dog类。也就是说List<? extends Animal>容器不能存储Animal的
所有子元素
所以List<? extends Animal>也不能添加元素。除了nul值。3)而List<? super Animal>是可以添加元素的。<? super Animal>是下限通配符。此参数类型可以是Animal和其所有父类
public void add(List<? super Animal> list){
list.add(new Cat("a", 12));
list.add(new Dog("a",24));
}
//调用方法
add(new ArrayList<Animal>); 此时容器可以存储Animal的所有子类元素,是一个参数类型确定的容器。