Java泛型讲解


前言 - 为什么要有泛型

在讲解泛型的使用之前 , 首先要明白 一个事情 , 就是为什么要有泛型 , 泛型的初衷是解决一个类只能传基本数据类型或指定数据类型的情况 .
  那么 想象这样一种情况 ,我想设计一个类 ,里面包含我一些常用的方法, 但是我不确定传过来的参数类型是什么,怎么解决?
答 : 使用Object 数组来接受 , object是所有类的父类 ,当然可以接受任意数据,但是我不光想要存,我还想要取出来用 ? 怎么取 , 有人会说 ,用Object 取出来,当然可以取出来,然后呢 在强制类型转换吗? 在你不知道Object数组中有哪些数据,你强制类型转换的数据未必是你需要的数据,jvm是不允许这种行为的,而且每次使用都强制类型转换也是很麻烦的事情 . 于是在这种需求的前提下, 泛型挺身而出.

一、泛型

泛型的优点

前面讲解了,为什么要有泛型 ,接下来就简单说一下,泛型的优点
优点1 : 在编译期间编译器自动给你做类型检查
优点2 : 在获取元素的期间,可以帮助我们进行类型转换

泛型的规定

1 :

泛型的使用

1 : 在给想要的类 ,加上 < > 就代表这个类是一个泛型类 ,在这个< >可以加一些形参, 泛型的形参并没有实际的作用,它的作用就是让你见名知意- 快速了解传过来的是一个什么类型

E 表示 Element - 元素类型
K 表示 Key
V 表示 Value
N 表示 Number
T 表示 Type
S, U, V 等等 -第二、第三、第四个类型

这里重要说明一下三种创建泛型的方式

1 : public T[] obj = new T[3]; 第一种 泛型是不允许泛型数组实例化的 , 为什么 - 因为 形参T只代表传过来的是一个类型 , 实际上并没有 T 这个数据类型 ,你没有办法实例化一个不存在的数据类型数组
2 : public E[] obj = (E[] ) new Object[3]; 第二种创建方式 能创建但是有缺陷,而且很大 ,这个缺陷是因为JAVA擦除机制而产生的 , 这里只说结果 - 上文说了 , 泛型只在程序的编译期间做检查 , 在程序的运行期间 经历了Java的擦除机制 , JVM 拿到的都是Object数组 , 所以使用第二种方式返回的是 Object数组 ,这样就和 直接创建Object数组一样了 ,JVM不会给你强制类型转换的机会
3 : public Object[] obj = new Object[3]; 正常方法 - 还是直接创建一个Object数组 ,只不过在方法返回值上, 强制类型转换为相对应的类型 .
这里问大家一个问题 ,方法直接返回E类型 ,和返回强制类型转换后的E类型有什么区别 ?
答 : 擦除机制 , 因为Java有擦除机制存在,编译完成后都擦除为Object数组 ,所以直接返回 - 返回的就是Object数组 ,而强制类型转换是在运行期间强制转换,返回的是E类型的数组


import java.lang.reflect.Array;


class MyArray<E> { // 1
    //T t;
    //public T[] obj = new T[3];
    //public E[] obj = (E[] ) new Object[3];

    /*
    以后常用的 !!!! 官方 自己在用的手段
    public Object[] obj = new Object[3];

    public E getPos2(int pos) {
        return (E)obj[pos];
    }*/

    public E[] obj;
    public MyArray(Class<E> clazz, int capacity) {
        //反射 - 最好的方式 - 后面讲反射
        obj = (E[]) Array.newInstance(clazz, capacity);
    }


    public E getPos(int pos) {
        return obj[pos];
    }
    public void setObj(int pos, E val) {
        obj[pos] = val;
    }
    public E[] getArray() {
        return obj;
    }
}
public class Test {
    public static void main(String[] args) {
        MyArray<Integer> myArray = new MyArray<>(Integer.class,10);
        myArray.setObj(0,10);
        myArray.setObj(1,78);
        Integer[] integers = (Integer[])myArray.getArray();

    }
    /*public static void main1(String[] args) {
        //实例化对象的同时 指定当前泛型类 的指定参数类型是Integer
        MyArray<Integer> myArray = new MyArray<>();
        //就可以存储 指定的数据类型
        myArray.setObj(0,10);
        myArray.setObj(1,78);
        myArray.setObj(2,66);

        Integer d = myArray.getPos(2);

        System.out.println("=================");

        MyArray<String> myArray2 = new MyArray<>();
        myArray2.setObj(0,"gaobo");
        myArray2.setObj(1,"bit");

        String str = myArray2.getPos(0);
    }*/
}

泛型的一些规定

1 : 泛型不能被实例化
2 : 泛型参数只能使用包装类
3 : 泛型不传类型参数 - 被称为裸类型-效果相当于直接创建Object数组

泛型的上界

上面讲了一些泛型的使用方法 , 但是这样的泛型依然存在 一些问题 ,比如 参数类型都是包装类 ,而我想要比较包装类数值大小的时候怎么办? 基本运算符号 ( > < == ) 只能比较基本数据类型 ,
在这种情况下 : 对传过来的参数类型是必要做一些约束的 - 所以泛型的上界出来了
在规定了泛型的上界的情况下 ,传过来的类型参数只能是 : 上界的子类 或 上界本身. ,
在这样情况下,就可以对参数类型做一定的约数,如果想要比较的时候,只要约定传过来的参数一定是实现了Comperto接口的类就行了.
注:泛型没有下界
注:没有指定上界-默认于上界为Object类

package genericdemo;


class Alg<E extends Comparable<E>> {
    public E findMax(E[] array) {
        E max = array[0];
        for(int i = 1; i < array.length;i++) {
            if(max.compareTo(array[i]) < 0 ) {
                max = array[i];
            }
        }
        return max;
    }
}
class A<E extends Number> {

}




public class Test2 {
    public static void main(String[] args) {
        Integer[] array = {1,4,2,10,9,8,17,5};
        Integer val = Alg3.findMax(array);
        System.out.println(val);
    }
    public static void main3(String[] args) {
        Alg2 alg2 = new Alg2();
        Integer[] array = {1,4,2,10,9,8,17,5};
        Integer val = alg2.<Integer>findMax(array);
        System.out.println(val);
    }

    public static void main2(String[] args) {
        A<Number> a1 = new A<>();
        A<Integer> a2 = new A<>();
        A<Double> a3 = new A<>();
        //A<String> a4 = new A<>();
    }
    public static void main1(String[] args) {
        Alg<Integer> alg = new Alg<>();
        Integer[] array = {1,4,2,10,9,8,17,5};
        Integer val = alg.findMax(array);
        System.out.println(val);
    }
}

泛型方法 了解

能实现泛型类 - 自然就能实现一个泛型方法,不同于泛型类 ,泛型方法在使用时 ,要声明传过来的参数类型
注: 在使用泛型方法的时候 ,最好将泛型方法声明为静态的

class Alg2 {

    public <E extends Comparable<E>> E findMax(E[] array) {
        E max = array[0];
        for(int i = 1; i < array.length;i++) {
            if(max.compareTo(array[i]) < 0 ) {
                max = array[i];
            }
        }
        return max;
    }
}

class Alg3 {
    public static <E extends Comparable<E>> E findMax(E[] array) {
        E max = array[0];
        for(int i = 1; i < array.length;i++) {
            if(max.compareTo(array[i]) < 0 ) {
                max = array[i];
            }
        }
        return max;
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值