了解的Java泛型
创始人
2024-02-11 15:27:23
0

作者:~小明学编程  

文章专栏:JavaSE基础

格言:目之所及皆为回忆,心之所想皆为过往
在这里插入图片描述

目录

前言

什么是泛型

为什么要引入泛型

使用泛型

裸类型

泛型类的定义

类型擦除

通配符

什么是通配符

通配符的上下界

通配符的使用

泛型中的父子类


前言

今天给大家带来的文章是Java中的泛型,对于泛型的学习主要是为了让我们能够去阅读Java中的底层源码。

什么是泛型

为什么要引入泛型

 我们随意的点开了我们ArrayList的源码我们就可以看到形如ArrayList的这种写法,我们可以把我们的数据类型当作参数传递给我们的类中,这样我们new对象的时候就比较的灵活了,就不会拘泥于一种类型了。

例如:

        ArrayList arrayList1 = new ArrayList<>();ArrayList arrayList2 = new ArrayList<>();

因为我们有泛型所以我们的ArrayList才能操作我们不同的数据类型,否则的话只能我们的ArrayList的类就只能操作一种类型,这样的话就很鸡肋,不够灵活。

使用泛型

class MyArray {public T[] object = (T[])new Object[10];public void set(int pos,T val) {this.object[pos] = val;}public T get(int pos) {return object[pos];}
}

这里我们自己定义了一个泛型的类里面有一个数组和两个方法。

    public static void main(String[] args) {MyArray myArray = new MyArray<>();myArray.set(1,"haha");String str = myArray.get(1);//这里自动的帮我们将Object的类型转换为StringSystem.out.println(str);}

然后我们new了一个对象,我们传入一个String类型,然后将我们数组中的1的下标给设置为"haha"。

public T[] object = (T[])new Object[10];

对于这行代码,写的其实不是很好但是基本实现了我们想要表达的东西,因为我们是Object类型的,所以这里要强转为我们的泛型的类型。

裸类型

前面说到泛型,那么与之对应的就是我们的裸类型

MyArray myArray = new MyArray();

裸类型就是在我们new一个对象的时候不给它传递我们的数据类型,这就会导致我们下面的问题

    public static void main(String[] args) {MyArray myArray = new MyArray();myArray.set(0,13);myArray.set(1,"haha");String str = (String) myArray.get(1);//这里我们必须进行一个强制类型的转换才能接受System.out.println(str);}

因为我们没有传递我们的数据类型,所以在我呢吧返回我们对象里面的数据的时候其实都是Object类型的,所以我们这里要进行一个强制类型的转换。

注意: 我们不要自己去使用裸类型,裸类型是为了兼容老版本的 API 保留的机制。

泛型类的定义

上面我们说到泛型可以传入我们的数据类型,但是有时候不是什么类型都能传入的,这个时候就需要我们传入的类型进行一个约束了。

语法

class 泛型类名称<类型形参 extends 类型边界> {}

其中类型边界表示我们的泛型类可以接受的类型参数的最高的父类。

示例

class C {}
class D extends C{}
class E extends D {}
class Demo {}

这里我们创建了四个类,其中我们的E继承了D,然后D继承C,然后我们的Demo类接受一个泛型的参数,参数的最高级别为D类,所以

 上面这幅图可以清楚的看到我们最高可以接受的参数类型为D类,然而我们的C是我们D的父类,所以这里就给报错了。

提醒

当我们没有指定我们的上界的时候例如

class MyArray

这时候就默认我们的上界为Object,此时我们可以传入任何的类型,同时也正是因为这个原因,所以我们才需要对其上界进行一个限制。

类型擦除

这里我们有必要说的一点就是泛型是作用在编译期间的一种机制,在我们代码的运行期间实际上是没有这么多的类型的,那么到底我们传入的T在运行的时候是什么类型呢?
   实际上我们运行期间的类型主要取决于我们的边界。

class MyArray {public T[] object = (T[])new Object[10];public void set(int pos,T val) {this.object[pos] = val;}public T get(int pos) {return object[pos];}
}

例如我们前面的这个代码我们前面说过没指定边界的话,就默认为Object,所以在代码的运行过程中我们的T就变成了Object。

class Demo {}

再如上面的这段代码,在我们代码运行的过程中,我们的T就是我们的边界D类型,即使我们传入的参数是C也一样。

这就是我们的类型擦除,也就是在我们运行的时候我们所传的参数类型会被替换为我们的类型上界,同时这个过程是发生在我们的编译期间的。

我们想要实现这样一个功能,有一个类然后类里面有一个方法可以求出我们不同类型数组的的最大值。

写法一:

class Ale> {public T getMax(T[] array) {T max = array[0];for (int i = 0; i < array.length; i++) {if (max.compareTo(array[i])<0) {max = array[i];}}return max;}
}

写法一是这样的,我们的T的上界是Comparable,为什么上界要写成这样呢?因为我们下面要对数组里面的元素进行一个比较,如果我们没有Comparable的话我们进行完类型擦除,T将会替换为Object,此时里面没有compareTo方法,无法进行比较。

    public static void main(String[] args) {Ale ale = new Ale<>();System.out.println(ale);Integer[] array = {9,3,2,65,34,77,457};Integer a = ale.getMax(array);System.out.println(a);System.out.println(Ale1.getMax(array));}

写法二:

class Ale1 {public static> T getMax(T[] array) {T max = array[0];for (int i = 0; i < array.length; i++) {if (max.compareTo(array[i])<0) {max = array[i];}}return max;}
}

第二种就是在我们的静态方法中使用泛型。

通配符

什么是通配符

 我们的源码中有很多形如上图的情况问号(?)是什么东西?

问号就是我们Java泛型中的通配符,

class Ale4 {public static void print2(ArrayList list) {for (Object x:list) {System.out.println(x);}}
}

形如上面这段代码,当我们传参的时候不知道传入什么的时候我们可以使用通配符?,这样我们就可以接受任何泛型类型的参数了。

class Ale3 {public static void print1(ArrayList list) {for (T x:list) {System.out.println(x);}}
}

当然像上面这样不用通配符写也是能够实现我们上述的功能的。

通配符的上下界

上界的写法

上界表示我们传入的类型最高只能是上界,上界的父类就不能传了。

下界的写法

下界表示我们传入的数据类型最低要求是下界,或者下界的父类

首先先来看看我们的上界的用法,

class Ale4 {public static void print2(ArrayList list) {for (Object x:list) {System.out.println(x);}}
}

我们通配符和泛型的参数类型一样可以接受上界以内的任何的参数类型,但是我们的泛型会被替换为具体的上界类型而我们的通配符则是对所有对象都适用。

通配符的使用

public static void main10(String[] args) {ArrayList arrayList = new ArrayList<>();arrayList.add(new Integer(12));}

我么的下界适合添加数据,因为因为最低都是Number那么作为我们Number的子类,肯定是能够添加进去的。

    public static void main10(String[] args) {ArrayList arrayList1 = new ArrayList<>();arrayList1.get(0);}

上界比较适合读入数据,因为我们返回的起码是Number,只要接受类型大于Number就行了。

泛型中的父子类

泛型中的父子类是根据我们通配符来决定的,例如

MyArrayList 是 MyArrayList 的父类型MyArrayList 是 MyArrayList 的父类型

那么我们就可以写出如下的代码

    public static void main(String[] args) {MyArray myArray1 = new MyArray<>();MyArray myArray = myArray1;}

因为我们的MyArrayList 是 MyArrayList 的父类型所以我们的myArray可以直接引用我们的myArray1。

最后:

这是个人对Java泛型的一些理解,对于泛型的学习可以不用学的很深,只要能看的懂我们的源码就行了,自己写代码的时候就更不要设计到泛型了,除非自己去设计jdk。

相关内容

热门资讯

630余家媒体集中发布2024...   2024年度媒体社会责任报告近日集中向社会发布。这是媒体社会责任报告工作开展以来,连续第12年发...
司机另收空调费是否正当?网约车...   近日,有网友在社交平台反映,乘坐特惠快车时遭遇了有偿开空调情况,车内告示标明“如需空调扫码3元,...
“苏超”发布处罚决定!   8月4日,江苏省城市足球联赛纪律委员会发布关于对连云港队、泰州队违规违纪的处罚决定:  来源:江...
广东佛山:即日起,在药店购买这... 日前,佛山市市场监管局发布《关于疫情防控期间加强零售药店销售重点管控药品登记管理的告知书》。 告知书...
这种水果热量低还能抗炎抗氧化 ...   夏季气候炎热  人体易耗气伤津  需通过饮食补充水分、维生素  并平衡电解质  桃子作为应季水果...
一块智能手表折射消费新变化   上半年,国内生产总值同比增长5.3%,比去年同期提高0.3个百分点。“我国经济基础稳、优势多、韧...
13岁妹妹打110“举报”姐姐...   13岁妹妹打110“举报”姐姐  把姐姐送去了派出所  网友得知真相后  纷纷点赞  咋回事? ...
上半年全国企业销售收入平稳增长...   中国青年报北京8月4日电(中青报·中青网记者 贾骥业)国家税务总局发布的最新数据显示,今年上半年...
烽火家书 | 孙晓梅:为理想斗...   七七事变后,日寇步步入侵  国土遭践踏,同胞遭屠戮  23岁的小学教师孙晓梅  与所有热血青年一...
老人被困红薯窖呼吸困难 有限空...   为了家里的猪,老人被困红薯窖  同伴见状赶来搭救  怎料也跌入其中  导致二人双双被困  据湖北...