java SE 之泛型

泛型

1、泛型

让一个类 / 方法,能够支持多种不同的数据类型

2、引入泛型

在实际的开发过程中,若要用一个普通类存储各种类型的数据,并不能实现,哪怕使用Object 类,也达不到理想效果。

public class Person {
    public String name;
    public int age;

    public Person (String name, int age){
        this.name = name;
        this.age = age;
    }
}
public class MyArray {
    private Object[] data = null;
    private int size = 0;
    private int capacity = 10;

    public void add(Object data){
        if(size >= capacity){
            return;
        }
        this.data[size++] = data;
    }

    public Object get(int index){

        return data[index];
    }

    public static void main(String[] args) {
        MyArray myArray = new MyArray();
        myArray.add(new Person("张三", 18));
        myArray.add(new Person("李四", 19));
        myArray.add(new Person("王五", 20));

        Person person = (Person) myArray.get(0);

        MyArray myArray2 = new MyArray();
        myArray2.add("hello");
        myArray2.add("world");
        String str = (String)myArray2.get(0);

        MyArray myArray3 = new MyArray();
        myArray3.add(1);
        String integer  = (String) myArray3.get(0);
    }
}

事实证明,使用 Object 来完成“泛型”,比较繁琐。
首先,需要写一些类型转换的代码。
其次,类型转换的代码容易出错,缺少一些必要的类型检查机制。

3、使用泛型

import org.omg.CORBA.Object;

//泛型版本实现数组封装类
//使用泛型时,类名后面需要加上 <E> 泛型参数, <> 表示当前这个类是泛型类.
//E 相当于是一个形参. E 表示某一种具体的类型,会在实例化的时候确定 E 具体是那种类型.
public class MyArray2 <E>{
    //创建的数组,类型不再使用 Object, 而是使用
    //
    private E[] data = null;
    private int size = 0;
    private int capacity = 10;

    public MyArray2(){
//        data = new E[capacity]; //由于 E 类型不确定,无法直接创建 E 类型的实例
        data = (E[])new Object[capacity];
    }

    public void add(E data){
        if(size > capacity){
            return;
        }
        this.data[size++] = data;
    }

    public E get(int index){
        return this.data[index];
    }


    public static void main(String[] args) {
//        MyArray2<String> myArray2 = new MyArray2<String>();
        //创建泛型实例,前后泛型的参数必须保持一致,但是后面的可以省略
        MyArray2<String> myArray2 = new MyArray2<>();
        myArray2.add("hello");
        myArray2.add("world");
        //此时获取元素的时候不需要类型转换
        String str = myArray2.get(0);

    }
}

使用泛型之后,在针对对象实例化的时候需要填写泛型参数的实际类型

MyArray2<String> myArray2 = new MyArray2<>();

此处实际类型会替换掉所有的泛型类型().

  • java的发泛型只能是引用类型.如果是内置内型,就需要使用对应的包装类(包装类也是引用类型)
  • java的泛型,本质上也是基于 Object 机制来实现的,private E[] data = null;本质上是一个Object[]
  • 泛型存在的意义就是帮助我们完成类型校验和类型转换.

4、类型边界

定义泛型类型的时候,对实例化时传入的参数类型加以限制;需要根据实际情况做出一些约束和校验.

public class MyArray2 <E extends Animal>{

当前 MyArray2 的类型参数必须设成 Animal 或者 Animal 的子类.

5、通配符

其功能和类型边界有点类似—限制泛型参数传入的条件.但是类型边界是在创建泛型类的时候参与的,而通配符是在泛型类使用的时候设计的,尤其是泛型类作为某个方法参数的时候涉及的.

    public static void print(MyArray2 <?> arr){
    }
此处的 ? 就是通配符,在调用print方法时,在此处可传入任意类型的泛型参数

5.1 通配符–上界

泛型参数为其父类或者是其子类

import org.omg.CORBA.Object;
public class MyArray2 < E >{

    private E[] data = null;
    private int size = 0;
    private int capacity = 10;

    public MyArray2(){
        data = (E[])new Object[capacity];
    }

    public void add(E data){
        if(size > capacity){
            return;
        }
        this.data[size++] = data;
    }

    public E get(int index){
        return this.data[index];
    }

    public static void print(MyArray2 <? extends Animal> arr){


    }
    
    public static void main(String[] args) {
        print(new MyArray2<String>());
        print(new MyArray2<Integer>());
        print(new MyArray2<Animal>());
        print(new MyArray2<Cat>());
    }

在这里插入图片描述

5.2 通配符–下界

泛型参数为其父类
在这里插入图片描述

5.3 总结

此处引入的类型边界,通配符以及通配符的上下界,都是"锦上添花",为了更充分的发挥泛型在编译器中的检查效果.

5.4 泛型中的父子类型

  • Object 是 Animal 的父类,Animal 是 Cat 的父类, 但是 MyArray 不是 MyArray 的父类,同理,MyArray 也不是 MyArray 的父类.
  • 为此使用通配符可以形成父子关系.
MyArray<?>MyArray<? extends Animal> 的父类型
MyArray<? extends Animal>MyArrayList<Dog> 的父类型
  • 是否具有父子关系可以用向上转型来验证.
    public static void func1(MyArray2<?> a1){

    }

    public static void func2(MyArray2<? extends Animal> a2){
        //此处的方法调用,相当于赋值
        MyArray2<?> a1 = a2;  //此处没报错是符合向上转型规则
        func1(a2);
    }

    public static void func3(MyArray2<Cat> a3){
        //此处的方法调用,相当于赋值
        MyArray2<? extends Animal> a2 = a3;  //此处没报错是符合向上转型规则
        func2(a3);
    }

    public static void main(String[] args) {

        func3(new MyArray2<Cat>());    
    }

6、类型擦除

其描述的是java泛型的底层实现原理.
泛型时一个语法糖而已,本质上底层是使用object完成的.
编译器在编译的过程中会自动记录泛型参数的实际类型,并且帮助开发者完成一些类型转换和类型校验工作.直到代码编译完成到了字节码中,此时就不再涉及到任何和泛型相关的信息.

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值