泛型语法+擦除机制+泛型的上界


泛型


一、 什么是泛型

1.能用于多种类型,把类型当做参数

JDK1.5后引入的

1.1 作用

在编译的时候

  • 存储数据的时候,进行自动的类型检查
  • 获取元素的时候,帮助进行类型转换
  • 泛型是编译时期的一种机制,在运行的时候没有泛型的概念

1.2 语法
class MyArray <T>{//当前类是一个泛型类

    //public Object[]  obj = new Object[5];//实现一个类,类中包含一个数组成员,\
    public T[] obj = (T[]) new Object[5];//

    // 使得数组中可以存放任何类型的数据,也可以根据成员方法返回数组中某个
    //下标的值?
    public T getPos(int pos) {
        return this.obj[pos];//回数组中某个
        //下标的值?
    }
    public void setObj(int pos,T val){
        this.obj[pos] = val;
    }
}

public class Test2 {
    public static void main(String[] args) {
        
        MyArray<Integer> myArray = new MyArray<>();//后面的<>可以省略
        //实例化对象的同时,指定当前的泛型类 的 指定参数类型为Integer
        //把类型进行了传递,只能存指定的数据类型
        //MyArray<Integer> myArray = new MyArray<Integer>();
        //指定的参数类型,必须是引用类型
        myArray.setObj(0,3);
        myArray.setObj(1,4);//这时就不能传String类型
        myArray.setObj(2,5);
        Object pos = myArray.getPos(1);
     //  double d = myArray.getPos(2);//不知道是什么类型的,取出的时候很麻烦
        //什么数据都能存储
        //传进去后,都向上转型常量object,获取数据的时候要强转
        //需要指定类型,才能不进行强转
        System.out.println(pos);
        System.out.println("-------------");
        MyArray<String> myArray1 = new MyArray<>();
        myArray1.setObj(1,"hello");
        //获取数据的时候不用强转,里面都是指定的数据类型,直接拿指定的类型接收
        myArray1.setObj(0,"Hello");
        String pos1 = myArray1.getPos(0);
        String pos2 = myArray1.getPos(1);
        //在编译的时候
        //存储数据的时候,进行自动的类型检查
        //获取元素的时候,帮助进行类型转换

    }
}
  • 类名后的 代表占位符,表示当前类是一个泛型类
  • 前面<>指定类型,后面的<>可以省略
  • 把类型进行了传递,只能存指定的数据类型
  • 指定的参数类型,必须是引用类型
  • 不能实例化一个泛型类型的数组
  • 裸类型:不加<>,兼容老版本的机制

E 表示 Element K 表示 Key V 表示 Value N 表示 Number


二、擦除机制

1. 为什么采用擦除机制实现泛型?

为什么Sun公司选择采用擦除机制实现泛型?

向后兼容性
  • 这种设计是为向后兼容性提供源代码和目标代码两方面的支持,希望现有的代码和类文件在新版本的Java中继续使用,而不发生冲突,在不破坏语言的同时,更改语言
移植兼容性
  • 移植兼容性要求API的泛型版本要和老的版本兼容,就是说用户能继续编译(源文件)和运行(编译后的程序)。这种要求在很大程度上限制了Java泛型设计的空间

2. 为什么不能使用“newT()”?

是因为,并不是每个类型都有一个空的构造器

  • Java是静态类型语言,不能简单的调用某一类型的空构造器,因为这个类型自身并不静态地知道有这样的构造器存在。由于擦除机制,所以没有办法来生成这种代码。

3. 创建类型T的数组

3.1 不安全的写法
T[] a = (T[]) new Object[N];

不安全,但可以在多数情况下运行,在编译时会警告
因为Object数组不是具体T类型的数组

如果方法返回T[],并且指定的类型是,将返回值存入String[]类型的变量中,在运行时将得到ClssCastException错误。

		 public T[] copyArr(T[] obj){
      		  return obj;
  	 	 }
        
        public static void main(String[] args) {
        Student<String> student = new Student<>();
        student.setObj(0,"小明");
        student.setObj(1,"小王");
        student.setObj(2,"小红");

        String[] copyArr = student.copyArr(student.obj);
        System.out.println(Arrays.toString(copyArr));
    }
Exception in thread "main" java.lang.ClassCastException: [Ljava.lang.Object; cannot be cast to [Ljava.lang.String;
	at learn.Test3.main(Test3.java:35)

返回的Object数组里面,可能存放的是任何的数据类型,可能是String,可能是Person,可能是Integer.运行的时候,直接转给String类型的数组,编译器认为是不安全的。

3.2 官方的写法
public Object[] obj =  new Object[5];//正确写法

  return (E) elementData[index];

在Java源码中,使用的是Object类型的数组,在方法中,返回时进行泛型的转换

3. 3 正确的写法

通过反射创建,实现类型的数组

/**
     * 通过反射创建,实现类型的数组
     * @param clazz
     * @param capacity
     */
    public Student(Class<T>clazz, int capacity) {
        this.obj = (T[])Array.newInstance(clazz,capacity);
    }
    Student<String> student = new Student<>(String.class,10);

4. 反编译后,对比方法的参数

在这里插入图片描述

  • 在运行的时候,没有泛型的概念
  • 泛型只是编译时期的一种机制
  • 编译完成后,会将泛类型擦除成了Object类型,叫做擦除机制
  • Java的泛型机制是在编译级别实现的。
  • 编译器生成的字节码在运行期间并不包含泛型的类型信息。

三、泛型的上界

  • 在定义泛型类时,有时需要对传入的类型变量做一定的约束,可以通过类型边界来约束。

public class MyArray<E extends Number>

E是number的子类 或者 E是Number本身

class Alg<E extends Comparable<E>> {}

代表将来指定的数据类型,一定实现了这个接口

点击移步博客主页,欢迎光临~

偷cyk的图

  • 4
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值