• Java初识泛型


    1. 什么是泛型
      泛型是jdk1.5引入的新语法,泛型就是适用于许多许多类型,就是对类型实现了参数化
    2. 实现一个类,类中包含一个数据成员,使得数组中可以存放任何类型的数据,也可以根据成员方法返回数组中某个下标的值
    class MyArray {
        public Object[] obj;
    //此时存储数据的时候,什么类型都可以存储
    //此时获取数据的时候,必须强转
    //思考:能不能指定放啥类型,这样就不要强转了——在类的后面加<>,并指定类型
        public MyArray() {
            obj = new Object[10];
        }
    
        public void setValue(int pos, Object value) {
            obj[pos] = value;
        }
    
        public Object getValue(int pos) {
            return obj[pos];
        }
    
    }
    
    
    public class Test {
        public static void main(String[] args) {
            MyArray myArray = new MyArray();
            myArray.setValue(1,12);
            myArray.setValue(0,"123");
    
            int a = (int)myArray.getValue(1);
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30

    这样写:
    ①此时存储数据的时候,什么数据都可以存储【比如int类型和String类型都可以存进去】

            myArray.setValue(1,12);
            myArray.setValue(0,"123");
    
    • 1
    • 2

    ②此时获取数据的时候,必须强制类型转换

            int a = (int)myArray.getValue(1);
    
    • 1

    思考:能不能指定放啥类型,然后就不需要强制类型转换了呢?——泛型!!!

    (虽然此时当前数组可以存放任何数据,但是我们还是希望数组只能持有一种数据类型,而不是同时持有这么多类型)所以,泛型的主要目的是:指定当前容器要持有什么类型的对象,让编译器去做检查。把类型作为参数传递,需要什么类型,就传入什么类型。

    1. 将上述程序修改成泛型类
    class MyArray<E> {
        public E[] obj = (E[]) new Object[10];
    
        public void setValue(int pos, E value) {
            obj[pos] = value;
        }
    
        public E getValue(int pos) {
            return obj[pos];
        }
    
    }
    
    
    public class Test {
        public static void main(String[] args) {
            MyArray<Integer> myArray = new MyArray<>();
            myArray.setValue(0,1);
            int a = myArray.getValue(0);
            System.out.println(a);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    ①此时只有指定的数据类型才可以存储

            MyArray<Integer> myArray = new MyArray<>();
            myArray.setValue(0,1);
            myArray.setValue(1,"abc0");//报错
    
    • 1
    • 2
    • 3

    因为此时在实例化对象的同时,指定了当前泛型类的指定参数类型是Integer【并且中鼎的参数类型必须是引用类型,放int就错了,int是基本数据类型】
    ②此时获取0下标存放的值没有发生强制类型转换

            int a = myArray.getValue(0);
            System.out.println(a);
    
    • 1
    • 2

    但是这里发生了自动装箱和拆箱操作。

    因此,泛型的好处/意义:
    1.存储数据的时候,可以帮我们进行自动的类型检查
    2.获取元素的时候,可以帮我们进行类型转换
    【注意以上2个好处/意义都是发生在编译的时候,泛型是编译时期的一种机制,在运行的时候没有泛型的概念。】

    1. 泛型的语法
      ①定义泛型类
    class 泛型类名称<类型形参列表>{
    
    }
    
    • 1
    • 2
    • 3

    注意:
    1、类名后的<>,比如代表占位符,表示当前类是一个泛型类,只相当于一个形参,实参是在实例化泛型类的时候给的。
    2、不能new泛型类型的数组
    规定:泛型当中不能去实例化一个泛型类型数组

    T[] t = new T[5]; //不能实例化泛型数组
    
    T[] t = (T[])new Object[5]; //对的,实例化Object类型数组,并且强制类型转换成泛型,但是不是足够好
    
    
    //这种方法是最好的
    Object[] obj = new Object[5]; //还是new Object对象
    public T getPos(int pos) {
    	return (T)obj[pos];  //在getset中再强转成T类型
    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    ②实例化泛型类对象

    	MyArray<Integer> list = new MyArray<Integer>();
    	泛型类<类型实参> 变量名      泛型类<类型实参>(构造方法实参)
    
    • 1
    • 2

    注意:泛型只能接受类,类型实参所有的基本数据类型必须使用包装类。
    关于省略类型实参:当编译器可以根据上下文推导的时候可以省略new后面的那个泛型实参

    	MyArray<Integer> list = new MyArray();//可以推导出实例化需要的类型实参为Integer
    
    • 1

    ③裸类型(左右两边的实参都省略了)
    裸类型是一个泛型类但是没有带类型实参。

    MyArray list = new MyArray();
    
    • 1

    理论上应该要报错,但是这里牵扯到Java的历史原因,裸类型是为了兼容老版本的API保留的机制。

    1. 泛型再Java中是怎么编译的?——擦除机制
      查看泛型程序的字节码文件
      在这里插入图片描述
      可以发现,在编译的过程中,将所有的E都替换成了Object,这种机制也叫擦除机制。
      擦除机制:运行的时候没有泛型,编译完成之后,泛型类型被擦除为Object类型,也就是说编译好之后E其实是一个Object。
      Java的泛型机制是在编译级别实现的,编译器生成的字节码在运行期间不包含泛型的类型信息。
      那么泛型只存在在编译的时候,并且在这个时候干了2件伟大而具有意义的事:【这也是和直接写Object的区别,泛型的好处】
      ①检查:检查是不是要的类型
      ②转换:去除了强制类型转换

    2. 泛型的上界
      泛型如果没有边界的话,都变成了Objetct。因此有时需要对传入的类型变量做一定的约束,通过类型边界来约束。(用到extends)
      ① 泛型的上界是类

      代表E是Number的子类,或者E是Number本身

    class A<T extends Number> {
        public T[] obj = (T[])new Object[10];
    }
    public class Test {
        A<Integer> a1 = new A<>();
        A<Double> a2 = new A<>();
        A<String> a3 = new A<>();  //报错
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    如代码A a3 = new A<>(); 会编译错误,因为String不是Number的子类类型。

    ②泛型的上界是接口
    >
    代表将来指定的参数E类型一定要实现了Comparable这个接口

    class AA<E extends Comparable<E>> {
    
    }
    
    class BB {
    
    }
    
    public class demo {
        AA<Integer> a1 = new AA<>();//不报错,因为Integer里面实现了Comparable接口
        AA<BB> a2 = new AA<>();//报错,因为BB类没有实现Comparable接口
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    代码AA a2 = new AA<>();会编译错误,因为BB类没有实现Comparable接口,但是Integer不会,因为Integer包装类实现了Comparable接口。
    在这里插入图片描述
    7. 泛型也可以用在方法中
    在返回值类型前加<>类型参数列表

        public <E>void swap(E[] array, int i, int j) {
            E tmp = array[i];
            array[i] = array[j];
            array[j] = tmp;
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    静态方法的泛型,需要在static后面<>声明泛型类型参数

        public static <E> void swap(E[] array, int i, int j) {
            E tmp = array[i];
            array[i] = array[j];
            array[j] = tmp;
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    关于调用泛型方法:
    使用类型推导和不使用类型推导

        public static void main(String[] args) {
            Test test = new Test();
            Integer[] array = {1,2,3};
            test.swap(array,1,2); //使用类型推导
            test.<Integer>swap(array,0,1);//使用类型推导
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
  • 相关阅读:
    Mac电脑专业raw图像处理 DxO PhotoLab 7中文最新 for mac
    什么是运营商网关取号​
    kubernetes 存储流程
    慧销平台ThreadPoolExecutor内存泄漏分析
    简单了解下最近正火的SwissTable
    异地恋挺痛苦的
    【算法|动态规划No.7】leetcode300. 最长递增子序列
    Redis的底层数据结构分析
    我用这10招,能减少了80%的BUG
    软件测试/测试开发丨接口自动化测试学习笔记,整体结构响应断言
  • 原文地址:https://blog.csdn.net/weixin_44070116/article/details/128056806