Java泛型

匿名 (未验证) 提交于 2019-12-02 21:52:03

1、什么是泛型


泛型就是 参数类型化 ,简单说就是在定义类 接口 方法时时不支持具体的参数类型的。只有在实际使用时才确定。

2、为何用泛型


我觉得有两点好处

public static void main(String[] args) {         List myList = new ArrayList();         myList.add(new Integer(1));         Integer value = (Integer)(myList.get(0));         System.out.println("value=" + value);     } 

 

Father<Teacher> fatherTeacher = new Father<>(new Teacher());Father<Doctor> fatherDoctor = new Father<>(new Doctor());
public class Father<T> {     private T job;          public Father(T job){         this.job = job;     }          public void work(){         System.out.println("my job is "+ job);     } } 

  

3、如何使用泛型


泛型可以使用在类(泛型类)、 接口(泛型接口、 方法(泛型方法)中。

泛型类: 如上述的例子

泛型接口

样例

public interface Work<T> {     public void work(T t); }  继承泛型接口 public class Father<T> implements Work<T>{     private T job;      public Father(T job){         this.job = job;     }      @Override     public void work(T t) {         System.out.println("my job is "+ t);     }  }
View Code

泛型方法:方法的参数调用时才确定

例如下 :在泛型类中定义了一个泛型方法 (E是一种类型,跟类中的T 可能一样可能不一样)

泛型方法必须使用<> 表示类型

public class Father<T> implements Work<T>{     private T job;      public Father(T job){         this.job = job;     }      @Override     public void work(T t) {         System.out.println("my job is "+ t);     }      public <E> void printWork(E e){         System.out.println("my job is "+ e);     } } 

  调用:

public static void main(String[] args) {         Father<Teacher> fatherTeacher = new Father<>(new Teacher());         fatherTeacher.printWork(new Teacher());     }
View Code

输出:my job is com.yangfei.test.fanxing.Teacher@13221655

4、泛型擦除


泛型只在编译时有效 运行时是没有泛型的,称之为泛型擦除。

如下的示例 输出结果为true (java中一个类只会加载一次 生成Class类型对象)

说明两个类是没有泛型的区别的(编译后都被转成了Object)。

Class list_int = new ArrayList<Integer>().getClass(); Class list_string = new ArrayList<String>().getClass(); System.out.println(list_int==list_string); 

  

泛型擦除的目的: 就是为了运行时不会创建过多的类 避免因泛型的区别导致加载的类泛滥。

泛型擦除非真正擦除: 否则运行时如何转换成实际的类型呢

List<String> sd = new ArrayList<String>();

sd.add("yangfei");

但取值的时候怎么知道要转成String类型的呢?

擦除并非真正的完全擦除,泛型信息还是会保存在class字节码的常量池中,

在使用了泛型的代码调用处会生成一个signature签名字段,signature指明了这个常量在常量池的地址,调用时强制转换

这样我们就找到了参数化类型。

https://www.jianshu.com/p/2ded3ffaa9c8

5、协变


数组是协变的 什么意思

如果class A extends B 那么B[] array = new A[] 也是成立的,这是协变。

泛型是不支持协变的

即 List<A>是不可以赋给List<B>的

6、 ?和T的区别


T表示一个类型 在使用时确定。

?时通配符 表示任意类型。

使用场景不一样

a. 在泛型类定义是使用T

Father<?> fatherTeacher = new Father<Teacher>(new Teacher());

有啥好处,我们知道泛型不支持协变的,有了通配符后,可以有如下表示

父子类:class Son extends Mather; 则如下写法也是合法的

List<? extends Mather> lists = new ArrayList<Son>(); 

其实List<?> 相当于List<? extends Object>

7、PECS原则


PECS原则的全拼 : "Producer Extends Consumer Super"

表示<? extends T> 一般用于生产者,生产数据。外部只从中读数据;< ? super T> 一般用于消费者,需要消费数据,外部需要往其中写数据。

7.1 <? extends T> 表示可能是T或者T的子类 (上边界通配符)

这种情况一般只能取 不能存非null之外的任何类型

如下class Son extends Mather; class Daughter extends Mather;

public static void main(String[] args) {         Mather[] matherArr = new Mather[]{new Daughter(),new Son()};         List<? extends Mather> lists = Arrays.asList(matherArr);         lists.add(null); //因为任何类型都可以用null表示         lists.add(new Daughter()); //此处会编译报错         Mather mather = lists.get(0);     } 

存非null值会报错 ,因为不知道具体是什么类型,Mather的子类和子类间并没有直接关系 没法赋值,所以没法存

取出来的值 只能是父类型(所有子类都可以转为父类)

7.2 <? super T> 表示可能是T或者T的父类 (下边界通配符)

这种情况一般只用于存数据 ,可以存T或T的子类,因为T的子类可以转换为T类型,而T类型也可以自动向上转为任何父类

public static void main(String[] args) {         Mather[] matherArr = new Mather[]{new Daughter(),new Son()};         List<? super Mather> lists = Arrays.asList(matherArr);         lists.add(null);         lists.add(new Daughter());         Object mather = (Object)lists.get(0);     } 

  

8、不支持泛型数组


List<String>[] array = new ArrayList<String>[5]; 

 为何不支持:数组支持协变,泛型运行时类型擦除,这样容易引起误解

如下: List<Integer>类型数组 因为类型参数,可以把List<String>也放入数组中,导致内容错误。

ArrayList<Integer>[] intArr = new ArrayList<Integer>[10]; Object[] obj = intArr;           ArrayList<String> listStr = new ArrayList<String>(); listStr.add("yangfei") obj[0] = listStr;          ArrayList<Integer> listInt = intArr[0]; Integer i = listInt.get(0);//想要获取Integer,但却是String 

https://www.cnblogs.com/hapjin/p/5371950.html

9、静态方法与类的泛型


如下:标红会编译报错

public class Father<T> implements Work<T>{     private T job;      public Father(T job){         this.job = job;     }      @Override     public void work(T t) {         System.out.println("my job is "+ t);     }      public static  void printWork(T e){         System.out.println("my job is "+ e);     }      } 

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!