java基础知识——24.泛型

这篇文章我们来讲一下java的泛型

目录

1.什么是泛型

1.1 泛型的概念

1.2 泛型的好处

1.3 粗看泛型集合的源码

2.泛型类

2.1 泛型类的定义

2.2 从泛型类派生子类

3.泛型接口

4.泛型方法

5.类型通配符

5.1类型通配符上限

5.2 类型通配符的下限

6.类型擦除

6.1无限制类型擦除

6.2有限制类型擦除

6.3桥接方法

7.泛型与数组

8.泛型和反射


1.什么是泛型

首先,我们来讲一下java推出泛型的背景

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

这样说可能不好理解,下面就用具体的例子来讲一下。

看如下代码:

首先,我们定义一个集合list,因为没有指定类型,所以java就默认为Object类型的,然后我们通过add方法,往里面添加元素,可以看到是可以添加的,因为在添加时进行默认的类型转换。然后我们将其输出打印,通过get方法可以获取到元素,因为里面都是Object类型的数据,所以我们定义一个Object类型的变量来接收。而对于集合中的元素,我们通常都是需要使用的,使用时就要用到明确的类型,所以我们可以将其强转为String类型,可以看到编译时没有报错,然后我们运行看一下结果

报错了,报的是ClassCastException错误,而我们可以明确的看到,在书写代码时,它没有报错,也就是说编译时没有报错,但是在运行时它报错了,这是很可怕的。

 通过这个例子,我们就可以看到,我们需要使用泛型

1.1 泛型的概念

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

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

下面用具体的例子来说明一下:

此时,我们调用add方法添加时,就指定添加的元素为String类型了

如果我们添加非String类型的数据就会在编译时报错了

下面写完,看一下运行结果:

1.2 泛型的好处

下面说一下泛型的好处:

  • 编译期间自动进行类型检查(类型安全)
  • 减少了数据类型的转换(消除了强制类型转换)

1.3 粗看泛型集合的源码

下面,我们来粗略的看一下泛型集合的源码

这是开头部分,我们可以看到源码中是<E>,这个E可以理解为一个形参,我们传入泛型的类型就会代替这个E,然后在代码中所有的E都会被我们传入的类型所替换。

2.泛型类

下面,我们来讲解一下泛型类

2.1 泛型类的定义

泛型类的定义语法如下:

class 类名称<类型标识,类型标识,…… >{
    private 泛型标识 变量名;
    …………
}

常用的泛型标识:T,E,K,V

注意:泛型标识可以理解为一种形参,或者直接点,就理解为一种类型

泛型类的使用:

使用语法:类名<具体的数据类型> 对象名 = new 类名<具体的数据类型>();

java1.7以后,后面<>中的具体的数据类型可以省略不写,那么使用语法就变为了:

类名<具体的数据类型> 对象名 = new 类名<>();

下面,通过具体实例来看一下:

这个就是很简单的一个泛型类的定义

这个是测试代码

没啥好说的,就是很简单指定类型,然后传入类型而已

注意事项:

  • 泛型类,如果没有指定具体的数据类型,此时,操作类型是Object
  • 泛型的类型参数只能是类类型,不能是基本数据类型
  • 泛型类型在逻辑上可以看出是多个不同的类型,但实际上都是相同类型

2.2 从泛型类派生子类

下面,我们来看一下从泛型类派生子类

如果子类也是泛型类,子类和父类的泛型类型要一致:

class ChileGeneric<T> extends Generic<t>

如果子类不是泛型类,父类要明确泛型的数据类型

class ChildGeneric extends Generic<String>

下面来看一下具体实例:

当子类不是泛型类的时候,和上面差不多

注意:在泛型中,你指定类型了,那就以指定的类型为准,没有指定类型,那就默认为Object类型

3.泛型接口

下面来讲一下泛型接口

泛型接口的定义语法:

interface 接口名称 <泛型标识,泛型标识,……>{
    泛型标识 方法名();
    ……
}

泛型接口的使用:

  • 实现类不是泛型类,接口要明确数据类型
  • 实现类也是泛型类,实现类和接口的泛型类型要一致

下面通过具体实例来看一下:

接口的测试和普通接口是一样的,这里就不多说了

4.泛型方法

下面来讲一下泛型方法

泛型方法,是在调用方法的时候指明泛型的类型(泛型类,是在实例化类的时候指明泛型类型)

语法格式:

修饰符<T,E,……>返回值类型 方法名(形参列表){
    方法体……
}

注意:

  • public与返回值中间的<T>非常重要,可以理解为声明此类方法为泛型方法。
  • 只有声明了<T>的方法才是泛型方法,泛型类中的使用了返校的成员方法并不是泛型方法。
  • <T>声明该方法将使用泛型类型T,此时才可以在方法中使用泛型类型T
  • 与泛型类的定义一样此处T可以随便写任意标识,常见的如T,E,K,V等形式参数常用于表示泛型

下面通过具体实例来看一下

 这就是一个泛型方法。注意,在泛型方法中,如果方法的形参或者方法里面都需要使用到泛型,那么泛型标识必须一致。

下面不写具体代码,就简单的思考一下。上面的泛型方法是写明了泛型标识符,我们知道,泛型就是用来规定类型的,方法的类型是与它的返回值有关的。如果,我们没有返回值,那么就可以不用写泛型标识了,此时只需要写void就可以了。其实就是很简单的一个内容。有返回值,那么必定要写明类型,于是就用到泛型;没有返回值,就没必要写类型,那就直接用void,就没泛型的事了

5.类型通配符

下面我们来讲一下类型通配符

什么是类型通配符?

类型通配符一般是使用“?”代替具体的类型实参,所以类型通配符是类型实参,而不是类型形参。

下面来看一下具体实例

如图所示,当我们类的泛型改变时,方法就不可以用了(注意:Integer是继承Number的,按照多态的思想,这里是可以通过的,但是在泛型这里,多态是不允许的,因为泛型类的本质是同一个类)

错误的解决方法:

如果再写一个方法,也会报错,因为这不构成方法的重载;如果将方法中的Number改为Object,也不行,因为不支持多态。

正确的解决方法:

使用泛型通配符

即如下图所示:

5.1类型通配符上限

下面,来讲一下通配符的上限

语法格式:

类/接口 <? extends 实参类型>

 要求该泛型的类型,只能是实参类型,或实参类型的子类型

下面通过具体例子来看一下:

如第13行所示,我们将里面的泛型改为<? extends Number>,意思是我们只能传Number或者Number的子类的类型,所以在第14行,我们就可以直接用Number类型的变量去接收(多态),这时,我们可以看到,当我们传入Integer时,没有报错,所以没有问题。

这就是所谓的类型通配符上限,它规定了泛型所能传入的类型的上限(或者说父类)是什么。

5.2 类型通配符的下限

下面,来讲一下通配符的上限

语法格式:

类/接口 <? super 实参类型>

要求该泛型的类型,只能是实参类型,或实参类型的父类型

下面通过具体例子来看一下:

如第13行所示,我们将里面的泛型改为<? super Integer>,意思是我们只能传Integer或者Integer的父类的类型,所以在第14行,我们就可以用Object类型的变量去接收(多态),这时,我们可以看到,当我们传入Number时,没有报错,所以没有问题。

这就是所谓的类型通配符下限,它规定了泛型所能传入的类型的下限(或者说子类)是什么。

6.类型擦除

下面,我们来讲一下java的类型擦除

概念:

泛型是Java 1.5版本才引进的概念,在这之前是没有泛型的,但是,泛型代码能够很好地和之前版本的代码兼容。那是因为,泛型信息只存在于代码编译阶段,在进入JVM之前,与泛型相关的信息会被擦除掉,我们称之为——类型擦除。、

下面我们来看一下例子:

结果为true,说明list1和list2是同一个类,也就是它两是同一类型,也就是说他们的类型(Integer和String)被擦除了

6.1无限制类型擦除

下面来看一下类型擦除的无限制类型擦除

意思就是我们在编写泛型类的时候,编写完后JVM在编译的时候,里面的泛型标识直接用Object来代替

6.2有限制类型擦除

下面来看一下类型擦除的有限制类型擦除

意思就是我们在编写泛型类的时候,如果用到泛型上限,那么编写完后JVM在编译的时候,里面的泛型标识直接用上限来代替

6.3桥接方法

桥接方法在接口中有用到,它是为了保持类和接口的实现关系

 

7.泛型与数组

下面我们来讲一下泛型数组

 泛型数组的创建

  • 可以声明待泛型的数组引用,但是不能直接创建带泛型的数组对象
  • 可以通过 java.lang.reflect.Array的newInstance(Class<T>,int)创建T[ ]数组

下面,通过具体例子来看一下:

这个是错误演示:

 正确方法:

这就是正确写法,如果再出现上面的错误,它就好显示错误了

另一种方法:

这就是第二种创建泛型数组的方法,可能比较难,但是仔细看是可以理解的

8.泛型和反射

最后我们来说一下泛型和反射

反射常用的泛型类:Class<T>;Constructor<T>

下面用具体实例来看一下:

没什么问题

至此,我们的泛型粗略的讲完了,在java中泛型是一个比较重要的章节,大家要掌握。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

L纸鸢

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值