泛型屋

一、泛型

1、泛型的优点

     jdk5加入,保证类型安全,使运行期错误提前到编译器

     消除强制类型转换(如果没有泛型,认为是一个Object,在转换时,非常容易出现ClassCastException)

    代码更灵活,可以复用

2、泛型的原理

      虚拟机不支持泛型,所以java实现的是一种伪泛型机制,也就是说java在运行生成字节,码编译器擦除了所有的泛型信息,这样java在不需要产生新的类型到字节码,所有的泛型类型最终都是一种原始类型,在java运行时根本不存在泛型信息。

 

二、泛型定义

1、泛型在类上

     实例看集合类

public interface List<E> extends Collection<E> {
    boolean add(E e);
}

总结:

  • 在我们new 对象的时候才传入泛型的类型
  • 类的泛型是在运行期确定的,可以作用于整个类中
  • 静态方法不可以访问定义在类上的泛型

2、泛型在方法上

(1)泛型定义在成员方法上

@SuppressWarnings("unchecked")
public <T> T[] toArray(T[] a) {
      if (a.length < size)
            // Make a new array of a's runtime type, but my contents:
            return (T[]) Arrays.copyOf(elementData, size, a.getClass());
      System.arraycopy(elementData, 0, a, 0, size);
      if (a.length > size)
         a[size] = null;
      return a;
}

(2)泛型定义在静态方法上(注意泛型的位置)

publicc  <T> static void  action(T t){

}

总结:

  • 泛型定义在方法上,在我们使用这个方法时确定泛型类型,因此作用范围就是这个方法,
  • 静态方法不可以访问类定义的泛型,因为类定义的泛型是初始化对象时确定,静态方法随类,不随类的对象

3、泛型定义在接口上

public interface Iterator<E> {
   
    boolean hasNext();

    E next();
}

4、通配符

(1)非限定通配符?(等价于? extends  Object)(一般用在方法上)

public static void  print(ArrayList<?>  list){
   Iterator<?> it=list.iterator();
   while(it.hasNext()){
     //it.next();
   }
}

(2)限定通配符(?extends  T,? super  T)

public class GenericBean<T> {

    private T data;

    public void  setData(T t){
        this.data=t;
    }
    
    public T getData(){
        return data;
    }
}

//Orange,Apple,Fruit关系
Orange  extends  Apple  extends  Fruit

   泛型限定有两种:

  • ? extends  E 可以接受E类型或者E的子类型,上限
  • set数据会编译错误,可以安全的获取数据,
  • get数据返回值类型是E本省
GenericBean<?  extends  Apple>  bean=new GenericBean<>();
bean.setData(new Apple());        //编译错误
bean.setData(new Orange());       //编译错误
bean.setData(new Fruit());        //编译错误

Apple data = bean.getData();
  • ? super E  可以接收E类型或者E的父类型,下限
  • set数据只能是本身和子类(因为子类可以安全转型为本身),不能是超类(超类不能安全转型)
  • get数据返回的是Object
GenericBean<? super  Apple>  bean=new GenericBean<>();
bean.setData(new Apple());
bean.setData(new Orange());
bean.setData(new Fruit());            //报错

 

三、 泛型    继承与子类型

1、

面试题:可以把List<String>  传递给一个接受List<Object> 参数的方法吗?       不能

               可以把List<String>  传递给一个接受Collecton<Object>参数的方法吗?    不能             

 

四、泛型擦除

1、检查泛型类型,获取目标类型

2、 擦除类型变量,并替换为限定类型

  •    如果泛型类型的类型变量没有限定,用Object作为原始类型
  •    如果有限定(T  extends  XClass) 则用XClass作为原始类型
  •    如果有多个限定(T  extends  XClass1&XClass2)则使用第一个边界XClass2作为原始类

3、在必要时插入类型转换以保持类型安全

4、生成桥方法以在扩展时保持多态性(当编译一个扩展参数化类的类,或一个实现了参数化接口的接口时,编译器有可能因此要创建一个合成方法,名为桥方法)

  说明:

  •   泛型擦除实例:
List<Integer> list=new ArrayList<>();
list.add(1);     //字节码运行,实际调用的是List.add(Object e),1先装箱成Integer

Integer x=list.get(0);
//字节码运行,实际调用的是Object obj=list.get(index);然后把Object强转成Integer,再进行拆箱操作
Integer y=(Integer)list.get(0);
int x=y.intValue();
  • 生成桥方法实例:
public  class  Plat<T>{
                             ---泛型擦除变成--->     void   set(Object  t);
    void set(T t);
}



public class AndroidPlat<T extends  Compare>  implement  Plat<T>{


    void  set(T t);          ------泛型擦除----->     void  set(Compare t);
    因为AndroidPlat实现了Plat接口得复写其方法,
    所以生成桥方法 set(Object t),但是实际调用的是参数为Compare类型的set方法,
    会把Object类型强转成Compare类型                                                      
} 

最后在类常量池保存了泛型信息,因此反射时可以正确获取泛型的类型

 

五、泛型的局限性

  •  泛型不能是基础类型,如果使用只能是基础类型的包装类    

         因为泛型擦除,最后泛型的原始类型是Object,Object不能存放基础类型。

  • 泛型不支持instanceOf关键字
ArrayList<String> list=new ArrayList<>();
list instanceOf  ArrayList<String>     报错 

   泛型擦除后类型丢失,是不能判断的。 

  •  泛型获取的class都是原生类型,无论传入的泛型是什么类型
ArrayList<String> list=new ArrayList<>();
ArrayList<Boolean> listBollean=new ArrayList<>();
Log.d("aaaa",""+(list.getClass()==listBollean.getClass()));   //true
  •   泛型数组可以 定义,但是不能初始化,会报错,编译不过
GenericBean<String>[] array=null;
array=new GenericBean<String>[10];

    如果A  extends  B,那么A[]的父类是B[],这是数组的协变,当泛型擦除后,数组无法协变,因此无法使用泛型数组。

//数组协变
Fruit[] fruit=new Fruit[10];
Apple[] apples=new Apple[10];
fruit=apples;
fruit[0]=new Apple();
fruit[1]=new Orange();   //可以编译,运行错误
  • 泛型类不能派生自Exception/Throwable

 

已标记关键词 清除标记
©️2020 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页