Java泛型与包装类实例分析

Java泛型与包装类实例分析

今天小编给大家分享一下Java泛型与包装类实例分析的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家参考一下,希望大家阅读完这篇文章后有所收获,下面我们一起来了解一下吧。

1、什么是泛型

泛型的本质是为了参数化类型(在不创建新的类型的情况下,通过泛型指定的不同类型来控制形参具体限制的类型)。

Java泛型与包装类实例分析

先看以下的例子:

我们以前学过的数组,只能存放指定类型的元素。如:int[] array=new int[10];String[] array=new String[10];而Object类是所有类的父类,那么我们是否可以创建Obj数组呢?

classMyarray{publicObject[]array=newObject[10];publicvoidsetVal(intpos,Objectval){this.array[pos]=val;}publicObjectgetPos(intpos){returnthis.array[pos];}}publicclassTestDemo{publicstaticvoidmain(String[]args){Myarraymyarray=newMyarray();myarray.setVal(1,0);myarray.setVal(2,"shduie");//字符串也可以存放Stringret=(String)myarray.getPos(2);//虽然我们知道它是字符串类型,但是还是要强制类型转换System.out.println(ret);}}

以上代码实现后,我们发现:

  • 任何类型的数据都能存放

  • 2号下标本来就是字符串,但是必须进行强制类型转换

以此引出泛型,泛型的目的就是:指定当前的容器要持有什么类型的对象,让编译器自己去检查。

2、泛型的语法

class 泛型类名称< 类型形参列表>{

//这里可以使用类型参数

}

泛型的使用:

泛型类<类型实参> 变量名=new 泛型类<类型实参>(构造方法实参)

MyArray list=new MyArray<>();

【注】

  • 类型后的<>代表占位符,表示当前类是一个泛型类

  • 在实例化泛型时,<>中不能是简单的类型,需要是包装类

  • <>不参与泛型的类型组成

  • 不能new泛型类型的数组

  • 使用泛型不需要进行强制类型转换

一个简单的泛型:

//此处T可以随便写为任意标识,常见的如T、E、K、V等形式的参数常用于表示泛型//在实例化泛型类时,必须指定T的具体类型publicclassTest<T>{//key这个成员变量的类型为T,T的类型由外部指定privateTkey;publicTest(Tkey){//泛型构造方法形参key的类型也为T,T的类型由外部指定this.key=key;}publicTgetKey(){//泛型方法getKey的返回值类型为T,T的类型由外部指定returnkey;}}

擦除机制:编译时会将<>中的类型擦除掉,所以<>中的东西不参与类型的组成。会将T擦除为Object。

为什么不能实例化泛型类型的数组?

数组和泛型之间的一个重要区别是它们如何强制执行类型检查。数组在运行时存储和检查类型信息,而泛型是在编译时检查类型错误。

返回的Object数组里面,可能存放着任何类型的数据,如string,通过int类型的数组来接收,编译器认为是不安全的。

3、泛型的上界

语法:

class 泛型类名称<T extends 类型边界>{

}

例:

public class MyArray{} //E只能是Number或Number的子类

public class MyArray<E extends Comparable<E>>{}

//E一定实现了Comparable接口的类

【注】没有指定边界的E,可以看作 E extends Object

4、通配符

? 用于在泛型的使用,即为通配符。通配符用来解决反泛型无法协变的问题。

如下两段代码:

代码一:publicstatic<T>voidprintList1(ArrayList<T>list){for(Tx:list){System.out.println(x);}}代码二:publicstatic<T>voidprintList2(ArrayList<?>list){for(Objectx:list){System.out.println(x);}}

代码2中使用了通配符,和代码1相比,此时传入代码1的具体是什么数据类型,我们是不清楚的。

(1)通配符的上界

语法:

<? extends 上界>

<? extends Number>//可以传入的实参类型为Number或Number的子类

例:对于以下关系,我们需要写一个方法来打印存储了Animal或者Animal子类的list。

Animal
Cat extends Animal
Dog extends Animal

代码一:

publicstatic<textendsAnimal>voidprint1(List<T>list>{for(Tanimal:list){System.out.println(animal);//调用了T的toString}}

此时T类型是Animal的子类或自己。

代码二:通过通配符实现

publicstaticvoidprint2(List<?extendsAnimal>list){for(Animalanimal:list){Syatem.out.println(animal);//调用了子类的toString方法}}

两种代码的区别:

  • 对于泛型实现的方法来说,<T extends Animal>对T进行了限制,只能是Animal的子类。传入Cat,就是Cat。

  • 对于通配符实现的方法来说,相当于对Animal进行了规定,允许传入Animal的子类。具体哪个子类,此时并不清楚。如:传入Cat,实际上声明的类型是Animal,使用多态才能调用Cat的toString方法

通配符上界&rarr;父子类关系:

//需要使用通配符来确定父子类型

MyArrayList<? extends Number>是MyArrayList<Integer>或者MyArrayList<Double>的父类

MyArrayList<?>是MyArrayList<? extends Number>的父类

ArrayList<Integer>arrayList1=newArrayList<>();ArrayList<Double>arrayList2=newArrayList<>();List<?extendsNumber>list=arrayList1;//list.add(1,1);//报错,此时list的引用的子类对象有很多,再添加的时候,任何子类型都可以,为了安全,java不让这样进行添加操作。Numbera=list.get(0);//可以通过Integeri=list.get(0);//编译错误,只能确定是Number子类

【注】

  • 不能对其进行添加,list中存储的可能是Number也可能是Number的子类,无法确定类型。

  • 通配符上界适合读取,不适合写入。

(2)通配符的下界

语法:

<? super 下界>

<? super Integer>//可以传入的参数类型是Integer或者Integer的父类

通配符下界的父子类关系:

MyArrayList<? super Integer>是MyArrayList<Intrger>的父类类型

MyArrayList<?>是MyArrayList<? super Integer>的父类

通配符下界适合写入元素,不适合读取。

5、包装类

在Java中,由于基本类型不是继承自Object,为了在泛型中可以支持基本类型,每个基本类型都对应了一个包装类。除了Integer和Character,其余基本类型的包装类都是首字母大写。

拆箱和装箱:

inti=10;//装箱操作,新建一个Integer类型对象,将i的值放入对象的某个属性中Integerii=i;//自动装箱//Integerii=Integer.valueOf(i);Integerij=newInteger(i);//显示装箱//拆箱操作,将Integer对象中的值取出,放到一个基本数据类型中intj=ii.intValue();//显示的拆箱intjj=ii;//隐式的拆箱

以上就是“Java泛型与包装类实例分析”这篇文章的所有内容,感谢各位的阅读!相信大家阅读完这篇文章都有很大的收获,小编每天都会为大家更新不同的知识,如果还想学习更多的知识,请关注恰卡编程网行业资讯频道。

发布于 2022-04-03 22:38:10
收藏
分享
海报
0 条评论
25
上一篇:原生JS怎么实现简单计算器功能 下一篇:怎么用CZGL.ProcessMetrics监控.NET应用
目录

    0 条评论

    本站已关闭游客评论,请登录或者注册后再评论吧~

    忘记密码?

    图形验证码