java范性详解_Java泛型解析,了解泛型使用

Java 泛型

泛型的本质是参数化类型。简单解释就是,将参数的数据类型也当作参数对待。泛型的目的就是为了写一套代码,可以到处通用,不用担心类型安全的问题。泛型可以用在类、接口、方法中对应的就是泛型类、泛型接口和泛型方法。

一、为什么要引入泛型?

我们先看一个例子:

f977bd2090a24d524d2b98a630e9e459.png

获取一个字符串对象,打印如下:

c499982bd9d23b56a595d74dc6130434.png

引入 Object 类型

这个类只能适用字符串类型,那要获取整型等其他数据类型怎么办呢?于是我们想到了 Object 类型,它可以表示所有 Java 类类型数据,于是改造下:

1acaeb0dec9c832bb427cb0ecb367b50.png

打印结果,字符串类型和上面的打印结果是相同的:

e11a23b657a0da6b5c58e61e0127a041.png

让方法返回一个 Object 类型数据,这样似乎就解决了问题。但还是有个问题,因为方法返回的是 Object 类,返回值参与其它类型数据的计算时需要强制类型转换。如:

a084a1be7003d275f83121e08f305fbc.png

使用泛型

Object 类型数据使用时需要事先知道参与计算的具体类型,有时候我们很难判断需要什么类型,如果写错了,那就会报错。为了少写代码,且不出错,于是就引入了泛型。通过泛型改造上面的类:

c3e6e23d616d6dd30dcee0a452ff1f80.png

打印结果:

37da03621c3b65b4eb2d7f7d4500f9ef.png

使用泛型后就不用强制转换数据类型,代码也变得通用了。

泛型的定义

使用泛型的方式有3种,分别是:

泛型类泛型方法泛型接口上面的代码中用的是 T 来代指数据类型,也就是泛型参数。T 不是唯一的,可以用任意大写字母替代,不过一般遵循如下原则:T:指一般的任何类。E:元素 Element 的意思,或者 Exception 异常的意思。K:键,Key 的意思。V:值,Value 的意思,通常与 K 一起配合使用。

泛型类,定义一个泛型类:

6509314677f40894b06c6280d8eac4aa.png

在类名后面需要用<>包裹,T 就是类型参数,多个类型参数,用不同的大写字母且“,”分隔。创建泛型类:

f43f47305464234c80a3e58ed8904b3d.png

<>中传入对应的类型,类中的 T 就会被对应的类型取代。

泛型方法,定义一个泛型方法:

5055bb9e60274b6979898ad9618ec7ac.png

泛型方法的定义是在返回类型前面加,返回类型也可以用泛型代指,如 T。方法中的类型化参数 T 不用<>。没有返回类型的泛型方法:

d9aaf02f8587037cee15650614622a89.png

泛型类和泛型方法可以同时使用,如:

cf111cf9eecb457b172dd2e1f0974b5e.png

泛型方法和普通方法的参数没有关联。

泛型接口

定义泛型接口:

4b8865dd37d8a1d60c70e6677fed346b.png

泛型接口和泛型类的定义类似。

泛型通配符?

有时我们会碰到这样的情况,一个夫类型的集合需要兼容子类,或者子类集合要兼容父类。如:

eaa1a355097867c971f06e5d5ebffaee.png

Integer继承自Number 类,但不代表 List继承自 List,泛型也没有继承关系,所以不能像变量类型一样兼容使用。但有时会又这类需求,于是引入?通配符:

extends T>上限通配符,指类型必须是 T 的子类,或 T 类型。

super T>下限通配符,指类型必须是 T 的父类,或 T 类型。 如:

8007dd765690036f44fdcec627b466ea.png

还有一种是无限通配符:>本质是 extends Object>,表示不知道什么类型。

f7d994d7d4ee10a8780ef4bc9934af2c.png

无限通配符可以方便使用但也是有限制的,无限通配符意味着不知道具体类型,所以数据只能读取,不能写入。如:

40ff86497f82d896f0185e4eb5a135ba.png

类型擦除

泛型只在编译阶段有效,编译后类型会被擦除。如:

ef17459f459cf74674a196800265b413.png

打印结果为 true,也即 l1 和 l2 的类型相同,都是java.util.ArrayList,泛型信息被擦除了。

泛型的限制

泛型不支持 8 中基本数据类型,需要用对应类型的包装类。

List l = new ArrayList<>(); // 编译报错

创建泛型类数组时只能创建无限定通配符的。

32ae0154e2b86c863af87268092972c4.png

因为类型擦除后就不知道数组中具体存储的哪种类型数据了。

泛型与反射

先看个例子:

0bc47e99fd9468d7246285cf0bda24b8.png

创建一个接受Integer类型的泛型数组 list,如果往 list 中插入String类型数据时编译出错,类型限制。看下 List 的 add 方法:

7036f273ccbaad4ae25f85b6bb2496f0.png

E代表任意类型,所以类型擦除后 add 方法就变成了如下方式:

boolean add(Object obj);

通过反射可以获取对象实例,并访问对象数据。如:

a3698173f42dc96195e9726a2faa8011.png

因为泛型的类型擦除性质,利用反射就可以绕过编译器的类型检查,这也说明了反射会引入安全问题,需要谨慎使用。

90b67b9c5f09e76477a45a13bc25c49a.png

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值