「这是我参与11月更文挑战的第17天,活动详情查看:2021最后一次更文挑战」。
泛型
1.泛型的作用与定义
类型的参数化,就是可以把类型像方法的参数那样传递。
泛型使编译器可以在编译期间对类型进行检查以提高类型安全,减少运行时由于对象类型不匹配引发的异常。
一说到泛型,大伙肯定不会陌生,我们代码里面有很多类似这样的语句:
1 | ini复制代码List list=new ArrayList<>(); |
ArrayList就是个泛型类,我们通过设定不同的类型,可以往集合里面存储不同类型的数据类型(而且只能存储设定的数据类型,这是泛型的优势之一)。“泛型”简单的意思就是泛指的类型(参数化类型)。想象下这样的场景:如果我们现在要写一个容器类(支持数据增删查询的),我们写了支持String类型的,后面还需要写支持Integer类型的。然后呢?Doubel、Float、各种自定义类型?这样重复代码太多了,而且这些容器的算法都是一致的。我们可以通过泛指一种类型T,来代替我们之前需要的所有类型,把我们需要的类型作为参数传递到容器里面,这样我们算法只需要写一套就可以适应所有的类型。最典型的的例子就是ArrayList了,这个集合我们无论传递什么数据类型,它都能很好的工作。
- Java泛型介绍
下面我们来介绍Java泛型的相关内容,下面会介绍以下几个方面:
- Java泛型类
- Java泛型方法
- Java泛型接口
Java泛型类
类结构是面向对象中最基本的元素,如果我们的类需要有很好的扩展性,那么我们可以将其设置成泛型的。假设我们需要一个数据的包装类,通过传入不同类型的数据,可以存储相应类型的数据。
Java泛型方法
前面我们介绍的泛型是作用于整个类的,现在我们来介绍泛型方法。泛型方法既可以存在于泛型类中,也可以存在于普通的类中。如果使用泛型方法可以解决问题,那么应该尽量使用泛型方法。下面我们通过例子来看一下泛型方法的使用:
1 | csharp复制代码class DataHolder<T>{ |
我们来看运行结果:
1 | 复制代码1AAAAA8.88 |
Java泛型接口
Java泛型接口的定义和Java泛型类基本相同,下面是一个例子:
1 | vbnet复制代码//定义一个泛型接口public interface Generator<T> { public T next(); |
此处有两点需要注意:
- 泛型接口未传入泛型实参时,与泛型类的定义相同,在声明类的时候,需将泛型的声明也一起加到类中。例子如下:
1 | typescript复制代码/* 即:class DataHolder implements Generator{ |
- 如果泛型接口传入类型参数时,实现该泛型接口的实现类,则所有使用泛型的地方都要替换成传入的实参类型。例子如下:
1 | typescript复制代码class DataHolder implements Generator<String>{ @Override |
从这个例子我们看到,实现类里面的所有T的地方都需要实现为String
1 | typescript复制代码/**Test01案例 |
泛型中通配符
我们在定义泛型类,泛型方法,泛型接口的时候经常会碰见很多不同的通配符,比如 T,E,K,V 等等,这些通配符又都是什么意思呢?
常用的 T,E,K,V,?
本质上这些个都是通配符,没啥区别,只不过是编码时的一种约定俗成的东西。比如上述代码中的 T ,我们可以换成 A-Z 之间的任何一个 字母都可以,并不会影响程序的正常运行,但是如果换成其他的字母代替 T ,在可读性上可能会弱一些。通常情况下,T,E,K,V,?是这样约定的:
- ?表示不确定的 java 类型
- T (type) 表示具体的一个java类型
- K V (key value) 分别代表java键值中的Key Value
- E (element) 代表Element
上界通配符 < ? extends E>
上届:用 extends 关键字声明,表示参数化的类型可能是所指定的类型,或者是此类型的子类。
在类型参数中使用 extends 表示这个泛型中的参数必须是 E 或者 E 的子类,这样有两个好处:
- 如果传入的类型不是 E 或者 E 的子类,编译不成功
- 泛型中可以使用 E 的方法,要不然还得强转成 E 才能使用
1 | java复制代码private <K extends A, E extends B> E test(K arg1, E arg2){ |
下界通配符 < ? super E>
下界: 用 super 进行声明,表示参数化的类型可能是所指定的类型,或者是此类型的父类型,直至 Object
在类型参数中使用 super 表示这个泛型中的参数必须是 E 或者 E 的父类。
dst 类型 “大于等于” src 的类型,这里的“大于等于”是指 dst 表示的范围比 src 要大,因此装得下 dst 的容器也就能装 src 。
上界通配符主要用于读数据,下界通配符主要用于写数据。
案例
1 | typescript复制代码//在Point类定义的时候完全不知道x和y的属性是什么类型,而由使用者来决定 |
泛型接口
1 | typescript复制代码//泛型接口的两种实现形式 |
泛型方法
1 | kotlin复制代码//在之前定义的类或接口上发现都可以在里面的方法在泛型类或接口里面,也可以单独定义 |
本文转载自: 掘金