爆肝预警!华为大佬耗时 1 天 1 夜整理的笔记,带你一文通关 java 泛型

今日分享开始啦,请大家多多指教~
泛型定义
通俗来讲,泛型就是泛泛的类型,没有特定的类型,在定义时需要传入某个类型,而只传入某一个特定的类型又限制了使用范围,所以传入一个泛型可以很好的解决这一尴尬的问题,本文从泛型的四个方面介绍,掌握了这四个方面,泛型的使用也就游刃有余了。说白了,泛型的实在就是一个类型占位符。相信大家在平时工作一定都使用过泛型,例如定义一个集合对象的时候。
示例:

泛型类
所谓的泛型类就是定义一个类时,为这个类中的变量,或者方法地形参指定一个通用的类型。
示例 1:
定义一个类,给类中的变量定义类型,这里我们不知道变量是什么类型,所以可以使用泛型,这里用 T 表示,当然你用任何一个字母表示都可以。

创建 User1 对象时,我们可以传入想要的类型。例如:


示例 2:
示例 1 中所有在参数都是一个类型,当然也可以指定不同的参数。

创建 User2 对象时,我们可以传入两个不同的类型。例如:

泛型方法
所谓的泛型方法就是方法的参数类型为一个泛型,分为普通的泛型方法和静态泛型方法。
普通的泛型方法
在定义普通的泛型方法有两种,一种是依赖于泛型类的传入的占位符,另一种是方法本身所持有的占位符。
示例:
在定义类时,给类中的方法形参指定类型。

调用时 say1()必须与泛型类的传入的类型一样,say2()则不受限制。例如:

静态的泛型方法
静态的泛型方法不依赖于泛型类的占位符,本身持有一个占位符。
错误示例:

正确示例:

泛型接口
泛型接口跟泛型类差不多,在定义接口时,指定一个占位符。实现类中可以指定占位符类型,也可以不指定,不指定时默认为 Object 类型。
示例 1:

如果实现类也不指定类型,也不使用默认的类型,那么就必须使用占位符,且和接口的占位符保持一致。
示例 2:

泛型擦除
java 类型通过编译生成字节码后,在反射的阶段会将类型中的泛型去掉,即所谓的泛型擦除,也就是说 java 中的泛型只存在于编码编译阶段,在运行期间泛型的类型会被擦除。这样做的目的是为了兼容 jdk 之前的版本。
示例:

通配符
泛型中也有继承,但其又区别于 java 中的继承。泛型中不认识 java 类中的泛型关系。所以这一块一定要注意。
示例 1:


按照 java 的概念去理解,user31 应该可以设置进去,但泛型实际上不支持。为了解决这个问题,就得使用通配符将 java 的中的继承关系重新绑定。通配符一般用?表示,可以理解为?是泛型中的父类。
示例 2:


虽然编译能通过,但是意义不大,因为使用的是?,泛型中可以传入任何类型的值,我们的设计的想法是能传入 Number 的子类。所以这里就涉及到泛型的上边界和下边界的问题。
上边界(extends)
针对上面的?的问题,其实我们是想传 Number 的子类,因此在使用通配符的时候给他加一个限制。也就是说使用 extends 后,传入的类型值必须是某一个具体的类子类才可以。
示例:


上边界,一般作用于读取 T 类型数据的时候,相当于儿子无法更改老子的曾经。
下边界 (super)
搞懂了上边界,下边界就好理解了,泛型中只要是某一个具体类的父类就可以了。
示例:


下边界,一般作用于写入 T 类型数据的时候,相当于老子为儿子打天下。
今日份分享已结束,请大家多多包涵和指点!
评论