image.png

泛型概念

泛型其实就是将类型参数化(即把要操作的数据类型当做一个参数),这样我们就可以在编译时就类,方法,接口的数据类型规定好了,减少了过多的向下转型,程序更加安全了。更通俗的讲,那垃圾分类举例子,一个垃圾桶,厂家生产的时候并没有给它规定,它里面只能放什么垃圾,这时的垃圾桶可以放任何垃圾,当我们确定了他只能放有害垃圾时,我们就给了他一个标签,他就只能放有害垃圾,其他的不行。
以我们的代码为例,就是如果我们需要在一个list中存放String类型的元素,就可以使用泛型,如果放入非String类型的数据,就会编译报错如下所以。

  1. public class test {
  2. public static void main(String[] args) {
  3. List<String> list = new ArrayList<>();
  4. list.add("a");
  5. list.add("b");
  6. //list.add(1); 编译出错,不能放入int类型
  7. }
  8. }

泛型的标记:E、T、K、V、N

  • E:在集合中使用,表示集合中存放的元素
  • T:表示Java类,所有的基本类和自定义的类
  • K:表示键(Key)
  • V:表示值(Value)
  • N:表示数值类型(Number)
  • ?:表示不明确的类型

    泛型上限、下限的限定

  • 泛型上限限定:< ? extends T>

用通配符?和关键字extends来规定泛型的上限,我们知道extends是继承的关键字,这里表示通配符?代表的类型是T的子类或者子接口
泛型下限限定:< ? super T>
用通配符?和关键字super来规定泛型的下限,在方法中super代表着父类,这里表示通配符?代表的类型是T的父类或者父接口

泛型类(在类上定义类型)

  1. public class Person<T> {
  2. private T t;
  3. public T getT() {
  4. return t;
  5. }
  6. public void setT(T t) {
  7. this.t = t;
  8. }
  9. }

我们看下测试方法,person1对象实例的set方法泛型设置的String类型,放入18时编译报错。person2对象实例的set方法设置为Integer类型放入18则不报错。
image.png

泛型接口(在接口上定义类型)

  1. public interface demo<T> {//泛型接口
  2. void test(T t);
  3. }
  4. public class demoImpl implements demo<String>{//清楚接口类型
  5. @Override
  6. public void test(String s) {
  7. System.out.println(s);
  8. }
  9. }
  10. public class demoImpl<T> implements demo<T>{//不清楚类型
  11. @Override
  12. public void test(T t) {
  13. System.out.println(t);
  14. }
  15. }

泛型方法(在方法参数上定义类型)

  1. public class test {
  2. public static void main(String[] args) {
  3. Person<Integer> person = new Person<>();
  4. person.setT(1);
  5. test(1,2,3,4);
  6. test("a","b","c","d");
  7. }
  8. public static <T> void test(T ... tArray ){
  9. for (T t : tArray) {
  10. System.out.print(t);
  11. }
  12. }
  13. }

泛型擦除

使用泛型时加上的类型参数,会被编译器在编译时去掉,这个过程就是泛型擦除。所以泛型主要用于编译阶段,编译后生成的class文件并没有泛型中的类型信息。
举个体现泛型擦除的例子,一目了然。
image.png
在编译前,list2是无法赋值给list的,因为此时的存在泛型的类型信息,list存放的String类型数据,list2存放的Integer类型,所以相互之间无法赋值。

  1. public class test {
  2. public static void main(String[] args) {
  3. ArrayList<String> list = new ArrayList<String>();
  4. list.add("a");
  5. ArrayList<Integer> list2 = new ArrayList<Integer>();
  6. list2.add(1);
  7. System.out.println(list.getClass() == list2.getClass()); //输出:true
  8. }
  9. }

删除赋值,查看编译之后的对象,果然相等,说明编译之后泛型的类型信息被擦除了。