一篇文章搞定Java泛型

目录

介绍

优点

泛型类

语法定义

代码示例 

泛型类注意事项

 抽奖示例

 泛型类派生子类

定义

代码示例

子类是泛型

 子类不是泛型

 泛型接口

定义

泛型方法

定义

 代码示例

 泛型方法与可变参数

泛型方法总结 

​编辑类型通配符

定义 

 代码示例

通配符的上限 

定义

代码示例

通配符的下限 

定义

 代码示例

 jdk中下限通配符的使用

 类型擦除

泛型与数组 

泛型与反射 

定义

代码示例 


介绍

JAVA推出泛型以前,程序员可以构建一个元素类型为Object的集合,该集合能够存储任意的数据类型对象,而在使用该集合的过程中,需要程序员明确知道存储每个元素的数据类型,否则很容易引发ClassCastException异常。

Java泛型(generics)是JDK5中引入的一个新特性,泛型提供了编译时类型安全监测机制,该机制允许我们在编译时检测到非法的类型数据结构。

泛型的本质就是参数化类型,也就是所操作的数据类型被指定为一个参数。

优点

类型安全

消除了强制类型的转换

泛型类

语法定义

一篇文章搞定Java泛型_第1张图片

 一篇文章搞定Java泛型_第2张图片

代码示例 

//  泛型标识--类型形参  T创建对象的时候指定具体的数据类型
public class Generic {
    //T 外部创建使用类的时候来指定  可以理解为 谁用谁定义
    private T key;

    public Generic() {}
    public Generic(T key) {
        this.key = key;
    }

    public T getKey() {
        return key;
    }

    public void setKey(T key) {
        this.key = key;
    }

    @Override
    public String toString() {
        return "Generic{" +
                "key=" + key +
                '}';
    }
}

 测试:一篇文章搞定Java泛型_第3张图片

 注意泛型类不支持基本数据类型 这点在编译时就会有报警提示

一篇文章搞定Java泛型_第4张图片

泛型类注意事项

一篇文章搞定Java泛型_第5张图片

 抽奖示例

public class ProdocGetter {

    Random random = new Random();

    //奖品
    private T product;

    //奖品池
    List list = new ArrayList<>();

    //添加奖品
    public void addPro(T t){
        list.add(t);
    }

    //随机抽奖
    public T getProduct(){
        return list.get(random.nextInt(list.size()));
    }

    public static void main(String[] args) {
        //创建抽奖器对象 指定奖品类型(数据类型)
        ProdocGetter stringProdocGetter = new ProdocGetter<>();
        String[] strings = {"苹果电脑","小米手机","奔驰汽车","迪迦奥特曼玩具"};
        //奖品池塞入奖品
        for (String pro : strings) {
            stringProdocGetter.addPro(pro);
        }
        //抽奖
        System.out.println("恭喜您,抽中了:"+stringProdocGetter.getProduct());

        System.out.println("分割线====================================");
        ProdocGetter intProdocGetter = new ProdocGetter<>();
        Integer[] integers = {100,500,9000,16645,30458};
        //奖品池塞入奖品
        for (Integer pro : integers) {
            intProdocGetter.addPro(pro);
        }
        //抽奖
        System.out.println("恭喜您,抽中了:"+intProdocGetter.getProduct()+"元");

    }
}

测试:

一篇文章搞定Java泛型_第6张图片

 泛型类派生子类

定义

一篇文章搞定Java泛型_第7张图片

代码示例

子类是泛型

父类泛型

public class Parent {
    private E value;

    public E getValue() {
        return value;
    }

    public void setValue(E value) {
        this.value = value;
    }
}

 子类泛型

//泛型类派生子类,子类也是泛型类,那么子类的泛型标识要和父类一致。
public class Child extends Parent{
    @Override
    public T getValue() {
        return super.getValue();
    }

    public static void main(String[] args) {
        Child child = new Child<>();
        child.setValue("我是一个字符串");
        System.out.println(child.getValue());
    }
}

测试:

一篇文章搞定Java泛型_第8张图片

注意此时的子类泛型是T,继承的父类也是T,而最原先定义的父类泛型是E

子类如果是泛型,那么必须指定父类泛型和子类是一致的

如果不一致:

一篇文章搞定Java泛型_第9张图片

 子类不是泛型

//泛型类派生子类 如果子类不是泛型,那么父类需要明确指定数据类型 如果不指定那么数据类型则为Object
public class ChildSecond extends Parent{
    @Override
    public Integer getValue() {
        return super.getValue();
    }

    @Override
    public void setValue(Integer value) {
        super.setValue(value);
    }

    public static void main(String[] args) {
        ChildSecond  childSecond = new ChildSecond();
        childSecond.setValue(1000);
        System.out.println(childSecond.getValue());
    }
}

测试:

一篇文章搞定Java泛型_第10张图片

 如果不明确指定父类的数据类型

一篇文章搞定Java泛型_第11张图片

 泛型接口

定义

一篇文章搞定Java泛型_第12张图片

 一篇文章搞定Java泛型_第13张图片

 泛型接口的代码示例和泛型类派生子类如出一辙,不再代码示例

泛型方法

定义

一篇文章搞定Java泛型_第14张图片

 代码示例

 还是以之前的例子,但是这里需要多定义一个泛型方法

public class ProdocGetter {

    Random random = new Random();

    //奖品
    private T product;

    //奖品池
    List list = new ArrayList<>();

    //添加奖品
    public void addPro(T t){
        list.add(t);
    }

    //随机抽奖
    public T getProduct(){
        return list.get(random.nextInt(list.size()));
    }

    //定义泛型方法
    public  E getProduct(List list){
        return list.get(random.nextInt(list.size()));
    }

    public static void main(String[] args) {
        ProdocGetter prodocGetter = new ProdocGetter<>();
        List strList = new ArrayList<>();
        strList.add("华为手机");
        strList.add("苹果手表");
        strList.add("空调");
        //泛型方法的调用 类型是通过调用方法的时候来指定
        String procut = prodocGetter.getProduct(strList);
        System.out.println(procut+"\t"+procut.getClass().getSimpleName());
        System.out.println("分割线=============================================>");
        ArrayList integers = new  ArrayList<>();
        integers.add(100);
        integers.add(30004);
        integers.add(6471);
        Integer integer = prodocGetter.getProduct(integers);
        System.out.println(integer+"\t"+integer.getClass().getSimpleName());
    }
}

测试:

一篇文章搞定Java泛型_第15张图片

 定义多个泛型类型的静态泛型方法一篇文章搞定Java泛型_第16张图片

 泛型方法与可变参数

一篇文章搞定Java泛型_第17张图片

 一篇文章搞定Java泛型_第18张图片

泛型方法总结 

一篇文章搞定Java泛型_第19张图片类型通配符

定义 

一篇文章搞定Java泛型_第20张图片

 代码示例

我们先看下数据类型Integer和Number的关系

点进Integer可以看到Integer是继承了Number

一篇文章搞定Java泛型_第21张图片

根据原先多态的想法,我们可以这样定义:

一篇文章搞定Java泛型_第22张图片

但是这里却报错了

一篇文章搞定Java泛型_第23张图片

也就是说泛型这里不可以使用多态来进一步转换类型数据,这个时候类型通配符的作用就显现出来了

一篇文章搞定Java泛型_第24张图片

通配符的上限 

定义

一篇文章搞定Java泛型_第25张图片

代码示例

书写三个继承关系类,Animal->BIgDog->Dog

Animal:

public class Animal {
}

 BIgDog:

public class BIgDog extends Animal{
}

Dog:

public class Dog extends BIgDog{
}

测试:

一篇文章搞定Java泛型_第26张图片

本次没有测试演示,可以看到此时定义的通配符上限类为BigDog,所以showAnimal中传递的集合数据类型只能由BigDog或者BigDog的子类,BigDog的父类Animal已经报警不可用

 一篇文章搞定Java泛型_第27张图片

需要注意的是通配符上限的集合是不允许填充实例数据的,比如:

一篇文章搞定Java泛型_第28张图片

因为此时定义了通配符的上限类,而集合根本不确定集合中存的数据是什么数据类型

通配符的下限 

定义

一篇文章搞定Java泛型_第29张图片

 代码示例

一篇文章搞定Java泛型_第30张图片

 可以看到此时定义的通配符下限类为BigDog,所以showAnimals中传递的集合数据类型只能由BigDog或者BigDog的父类,BigDog的子类Dog已经报警不可用

通配符下限这里集合是可以直接添加实例的

一篇文章搞定Java泛型_第31张图片

 jdk中下限通配符的使用

改造三个类

Animal

public class Animal {
    public String name;

    public Animal(String name) {
        this.name = name;
    }

    @Override
    public String toString() {
        return "Animal{" +
                "name='" + name + '\'' +
                '}';
    }
}

BigDog

public class BIgDog extends Animal{

    public Integer age;

    public BIgDog(String name, Integer age) {
        super(name);
        this.age = age;
    }

    @Override
    public String toString() {
        return "BIgDog{" +
                "age=" + age +
                ", name='" + name + '\'' +
                '}';
    }
}

Dog

public class Dog extends BIgDog{

    public Integer level;

    public Dog(String name, Integer age, Integer level) {
        super(name, age);
        this.level = level;
    }

    @Override
    public String toString() {
        return "Dog{" +
                "level=" + level +
                ", age=" + age +
                ", name='" + name + '\'' +
                '}';
    }
}

TreeSet中的有一个构造函数就是典型的通配符下限使用

一篇文章搞定Java泛型_第32张图片

 测试:

一篇文章搞定Java泛型_第33张图片

一篇文章搞定Java泛型_第34张图片

 一篇文章搞定Java泛型_第35张图片

 类型擦除

一篇文章搞定Java泛型_第36张图片

 一篇文章搞定Java泛型_第37张图片

 一篇文章搞定Java泛型_第38张图片

 一篇文章搞定Java泛型_第39张图片

泛型与数组 

一篇文章搞定Java泛型_第40张图片

泛型与反射 

定义

一篇文章搞定Java泛型_第41张图片

代码示例 

一篇文章搞定Java泛型_第42张图片

你可能感兴趣的:(java,设计模式,java,开发语言,泛型,通配符)