# 泛型概述
当增加了泛型的集合,可以记住集合中元素的类型,也可以检查元素的类型。
泛型的好处有:
- 可以记住元素类型,避免强制类型转换,使代码更加简洁
- 可以对元素类型进行检查,避免异常的发生,增加代码健壮性
# 泛型的使用
语法
// 指定一种类型
<类型>
// 指定多种类型
<类型, 类型, ···, 类型>
1
2
3
4
5
2
3
4
5
这样的写法又被称为“菱形”语法,它更好地简化了泛型编程。
父类名|接口名<类型> 变量名 = new 父类名|接口名<> {
···
}
1
2
3
2
3
# 泛型类
语法
[修饰符] class 类名<类型形参> {
···类型形参···
}
1
2
3
2
3
其中,类型形参可以为任意标识,常用:T、E、K、V
说明
虽然只定义了一个 类名<类型形参>
类,但在实际使用时可以根据泛型实参的不同产生无数个类。
示例
public class Container<T> {
private T parameter;
public T getParameter() {
return parameter;
}
public void setParameter(T parameter) {
this.parameter = parameter;
}
}
public class Test {
public static void main(String[] args) {
// 不传入实参
Container a = new Container();
a.setParameter(123);
System.out.println(a.getParameter());
a.setParameter("123");
// 需要进行强制类型转换
String temp1 = (String) a.getParameter();
System.out.println(temp1);
System.out.println("------");
// 传入实参
Container<String> b = new Container<>();
// b.setParameter(123);
System.out.println(b.getParameter());
b.setParameter("123");
// 无需强制类型转换
String temp2 = b.getParameter();
System.out.println(temp2);
}
}
// 输出结果
123
123
------
null
123
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
# 泛型接口
语法
[修饰符] interface 接口名<类型形参> {
···类型形参···
}
1
2
3
2
3
其中,类型形参可以为任意标识,常用:T、E、K、V
说明
虽然只定义了一个 接口名<类型形参>
接口,但在实际使用时可以根据泛型实参的不同产生无数个接口,因此可以:
- 根据需要重写不同参数的方法
- 与泛型类相接口,使得泛型类也可以实现泛型接口
示例
public interface Echo<T> {
void echo(T parameter);
}
1
2
3
2
3
根据需要重写不同参数的方法
public class Test implements Echo<String>{
@Override
public void echo(String parameter) {
System.out.println(parameter + "," + parameter);
}
public static void main(String[] args) {
Test test = new Test();
test.echo("Hello");
}
}
// 输出结果
Hello,Hello
1
2
3
4
5
6
7
8
9
10
11
12
13
14
2
3
4
5
6
7
8
9
10
11
12
13
14
泛型类实现泛型接口
public class Test2<T> implements Echo<T> {
@Override
public void echo(T parameter) {
System.out.println(parameter + "," + parameter);
}
public static void main(String[] args) {
Test2<String> test2 = new Test2<>();
test2.echo("world");
}
}
// 输出结果
world,world
1
2
3
4
5
6
7
8
9
10
11
12
13
14
2
3
4
5
6
7
8
9
10
11
12
13
14
# 泛型方法
语法
[修饰符] <类型形参> 返回值类型 方法名(类型形参 参数名){
方法体
return 返回值;
}
1
2
3
4
2
3
4
其中,类型形参可以为任意标识,常用:T、E、K、V
说明
虽然只定义了一个方法,但在实际使用时根据泛型实参的不同可以适用于各种类型的数据。
与泛型类、泛型接口的区别在于:
- 泛型类、泛型接口中,泛型形参在整个接口、类中有效 泛型方法中,泛型形参仅在方法中有效
- 泛型类、泛型接口在创建对象、声明变量时显式指定泛型实参
泛型方法可以在调用方式时由系统根据传入参数判断泛型实参
示例
public class Test {
public static void main(String[] args) {
doubleCall("123");
doubleCall(123);
doubleCall(66.6);
}
public static <T> void doubleCall(T parameter) {
System.out.println(parameter.getClass());
System.out.println(parameter + "+" + parameter);
}
}
// 输出结果
class java.lang.String
123+123
class java.lang.Integer
123+123
class java.lang.Double
66.6+66.6
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# 泛型构造器
语法
[修饰符] <类型形参> 类名<类型形参> {
···类型形参···
}
1
2
3
2
3
其中,类型形参可以为任意标识,常用:T、E、K、V
说明
与泛型方法类似,可以在调用时根据参数推断泛型形参的类型,也可以显式指定泛型形参的类型。
示例
public class Test {
public <T> Test(T parameter) {
System.out.println(parameter);
}
public static void main(String[] args) {
Test test = new Test("abc");
}
}
// 输出结果
abc
1
2
3
4
5
6
7
8
9
10
11
12
2
3
4
5
6
7
8
9
10
11
12
# 类型通配符
为了表示泛型类的父类,可以使用类型通配符 ?
。
泛型类<?>
1
void fun(List<?> list) {
···
}
// 可以传入任意类型的泛型类实例
fun(list<String>)
fun(list<Double>)
fun(list<Object>)
fun(list<Student>)
1
2
3
4
5
6
7
8
2
3
4
5
6
7
8
调用方法时,可以传入任意类型的泛型类实例,因为 泛型类<?>
是所有泛型类实例的父类,因此可以接受任意类型的泛型类实例。
上限类型通配符
泛型类<? extends 父类名>
1
只能匹配类型为父类名的子类的泛型类实例,因此可以把父类名看作上限。
下限类型通配符
泛型类<? super 子类名>
1
只能匹配类型为子类名的父类的泛型类实例,因此可以把子类名看作下限。
# 泛型方法的重载
泛型允许设定通配符的上限和下限,因此允许在一个类中包含两个方法的定义,从而实现了泛型方法的重载。
[修饰符] <类型形参1> 返回值类型 方法名(类型形参1 参数名){
方法体
return 返回值;
}
[修饰符] <类型形参2> 返回值类型 方法名(类型形参2 参数名){
方法体
return 返回值;
}
1
2
3
4
5
6
7
8
2
3
4
5
6
7
8
public class Test {
static <T extends Double> void fun(T parameter) {
System.out.println("Double");
}
static <T extends Integer> void fun(T parameter) {
System.out.println("Integer");
}
static <T extends String> void fun(T parameter) {
System.out.println("String");
}
public static void main(String[] args) {
Test.fun(66.6);
Test.fun(123);
Test.fun("123");
}
}
// 输出结果
D:\Test
D:\Test\hello
D:\Test\hello
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
← Java面向对象-集合 Java机制-异常 →