Java 泛型
本文最后更新于:2024年3月18日 凌晨
Java 泛型
泛型简介
- 泛型是Java语言的新特性,泛型的本质是参数化类型,也就是说,程序中的数据类型被指定为一个参数,泛型可以用在类,接口和方法的创建中,分别称为泛型类,泛型接口,泛型方法,下面给出了一个简单的使用泛型的例子,其中,
<>
之间定义形式类型参数。
[例14-1]:泛型的简单使用示例。
1 |
|
- Java SE1.5之前的Java版本不支持泛型,系统为实现方法参数的通用性,一般将参数定义为Object类型,我们知道,任何对象均可传递给Object类型引用变量,从而实现参数的"任意化”,但是要将对象转换为原有类型就必须使用强制类型转换。
- 泛型在定义时不指定参数的类型,用的时候来确定,这增加了程序的通用性,起到了程序"模版”化的效果,泛型的好处是在编译时检查类型安全,并且所有的强制类型转换都是自动和隐式的,泛型在使用中还有一些如下规则和限制:
- 泛型的类型参数只能是类(包括自定义类),不能是简单类型。
- 泛型的类型参数可以有多个,例如,Map<K,V>
- 泛型的参数类型可以使用extends语句,例如
<T extends Numbe>
,extends并不代表继承,它是类型范围限制,表示T<=Number
- 泛型的参数类型还可以是通配符类型,例如,
ArratList<? Extends Number>
,表示Number范围的某个类型,其中"?”代表未定类型。
泛型方法
- 你可以写一个泛型方法,该方法在调用时可以接收不同类型的参数,根据传递给泛型方法的参数类型,编译器适当地处理每一个方法调用。
- 下面是定义泛型方法的规则:
- 所有泛型方法声明都有一个类型参数声明部分(由尖括号分隔),该类型参数声明部分在方法返回类型之前(在下面例子中的
<E>
) - 每一个类型参数声明部分包含一个或多个类型参数,参数间用逗号隔开,一个泛型参数,也被称为一个类型变量,是用于指定一个泛型类型称的标识符。
- 类型参数能被用来声明返回值类型,并且能作为泛型方法得到的实际参数类型的占位符。
- 泛型方法体的声明和其他方法一样,注意类型参数只能代表引用型类型,不能是原始类型(像int,double,char的等)
- 所有泛型方法声明都有一个类型参数声明部分(由尖括号分隔),该类型参数声明部分在方法返回类型之前(在下面例子中的
实例
- 下面的例子演示了如何使用泛型方法打印不同字符串的元素:
1 |
|
- 编译以上代码,运行结果如下所示:
1 |
|
有界的类型参数
- 可能有时候,你会想限制那些被允许传递到一个类型参数的类型种类范围,例如,一个操作数字的方法可能只希望接受Number或者Number子类的实例,这就是有界类型参数的目的。
- 要声明一个有界的类型参数,首先列出类型参数的名称,后跟extends关键字,最后紧跟它的上界。
实例
- 下面的例子演示了"extends"如何使用在一般意义上的意思"extends"(类)或者"implements"(接口),该例子中的泛型方法返回三个可比较对象的最大值。
1 |
|
- 编译以上代码,运行结果如下所示:
1 |
|
泛型类
- 泛型类的声明和非泛型类的声明类似,除了在类名后面添加了类型参数声明部分。
- 和泛型方法一样,泛型类的类型参数声明部分也包含一个或多个类型参数,参数间用逗号隔开,一个泛型参数,也被称为一个类型变量,是用于指定一个泛型类型名称的标识符,因为他们接受一个或多个参数,这些类被称为参数化的类或参数化的类型。
实例
- 如下实例演示了我们如何定义一个泛型类:
1 |
|
- 编译以上代码,运行结果如下所示:
1 |
|
通配符与类型参数
- 本质下面几种符号都是通配符,只不过是编码时的一种约定俗成的东西,通常情况下,T,E,K,V,? 是这样约定的:
T
(type)表示具体的一个 Java 类型。K V
(key value)分别代表 Java 键值对中的Key ValueE
(element)代表Element?
表示不确定的 Java 类型。
1 |
|
- 输出结果为:
1 |
|
解析:因为getData()
方法的参数是List类型的,所以name, age, number都可以作为这个方法的实参,这就是通配符的作用。
类型通配符上限
< ? extends E>
:在类型参数中使用 extends 表示这个泛型中的参数必须是 E 或者 E 的子类。- 如果传入的类型不是 E 或者 E 的子类,编译不成功。
- 泛型中可以使用 E 的方法,要不然还得强转成 E 才能使用。
实例
1 |
|
- 输出结果:
1 |
|
解析:在1
处会出现错误,因为getUperNumber()
方法中的参数已经限定了参数泛型上限为Number,所以泛型为String是不在这个范围之内,所以会报错。
类型通配符下限
< ? super E>
:用 super 进行声明,表示参数化的类型可能是所指定的类型,或者是此类型的父类型,直至 Object
1 |
|
通配符 ? 与 T 的区别
T
是一个确定的类型,通常用于泛型类和泛型方法的定义。?
是一不确定的类型,通常用于泛型方法的调用代码和形参,不能用于定义类和泛型方法。
通过 T 来确保泛型参数的一致性
1 |
|
T 可以多重限定而 ? 不行
1 |
|
- 使用
&
符号设定多重边界(Multi Bounds),指定泛型类型 T 必须是MultiLimitInterfaceA
和MultiLimitInterfaceB
的共有子类型,此时变量 t 就具有了所有限定的方法和属性,对于通配符来说,因为它不是一个确定的类型,所以不能进行多重限定。
? 可以使用超类限定而 T 不行
- T 只具有一种类型限定方式:
1 |
|
- 但是通配符 ? 可以进行两种限定:
1 |
|
Class<T>
和 Class<?>
区别
Class<T>
在实例化的时候,T
要替换成具体类。Class<?>
它是个通配泛型,?
可以代表任何类型,所以主要用于声明时的限制情况。
1 |
|
- 所以当不知道定声明什么类型的 Class 的时候可以定义一个
Class<?>
- 那如果也想
public Class<T> clazzT;
这样的话,就必须让当前的类也指定T
1 |
|
本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!