一 为什么要引入泛型这个概念?
这里我用一个实例来简单说明。比如说:我们要设计一个表示二维坐标的类,但是因为关于坐标的表示有多种形式,比如:
(1)整数表示:x=10 y=20
(2)浮点型表示:x=10.5 y=20.8
(3)字符串表示:x=””东经 50度”” y=”北纬 79度”
因此,在我们设计的类中就不能单一的设置成int,float或String,而想要使用一个类型来接收这三种不同的数据类型,就只能使用Object。测试代码如下:
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
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
|
package
javase.paradigm;
/**
* 二维坐标表示
* */
public
class
Point {
private
Object X;
private
Object Y;
public
Object getX() {
return
X;
}
public
void
setX(Object x) {
X = x;
}
public
Object getY() {
return
Y;
}
public
void
setY(Object y) {
Y = y;
}
public
static
void
main(String[] args) {
Point point =
new
Point();
//1 整数表示坐标
point.setX(
10
);
//int --> Integer --> Object
point.setY(
20
);
int
x = (
int
) point.getX();
int
y = (
int
) point.getY();
System.out.println(
"整数表示,X坐标是:"
+ x +
",Y坐标是:"
+ y);
System.out.println(
"******************我是华丽的分割线**********************"
);
//2 小数表示坐标
point.setX(
10
.5f);
//float --> Float --> Object
point.setY(
20
.8f);
float
x2 = (
float
) point.getX();
float
y2 = (
float
) point.getY();
System.out.println(
"小数表示,X坐标是:"
+ x2 +
",Y坐标是:"
+ y2);
System.out.println(
"******************我是华丽的分割线**********************"
);
//3 字符串表示坐标
point.setX(
"东经 50度"
);
//String --> Object
point.setY(
"北纬 79度"
);
String x3 = (String) point.getX();
String y3 = (String) point.getY();
System.out.println(
"字符串表示,X坐标是:"
+ x3 +
",Y坐标是:"
+ y3);
}
}
|
输出:
1
2
3
4
5
|
整数表示,X坐标是:
10
,Y坐标是:
20
******************我是华丽的分割线**********************
小数表示,X坐标是:
10.5
,Y坐标是:
20.8
******************我是华丽的分割线**********************
字符串表示,X坐标是:东经
50
度,Y坐标是:北纬
79
度
|
通过上面设计的这个类貌似已经解决我们的需求了?但是真的是这样吗?这个类中将变量设置成Object类型,就意味着可以使用任意的Object子类来初始化,如果对变量初始化的类型和取出类型不一致,则程序在运行时会报错,出现类型转化异常。比如说这样:
1
2
3
4
5
6
|
point.setX(
0
);
point.setY(
"北纬179度"
);
int
x4 = (
int
) point.getX();
int
y4 = (
int
) point.getY();
//错误代码
System.out.println(
"错误案例,X坐标是:"
+ x4 +
",Y坐标是:"
+ y4);
|
这段代码编译没有问题,但是运行时报错,报错信息如下:
1
2
|
Exception in thread
"main"
java.lang.ClassCastException: java.lang.String cannot be cast to java.lang.Integer
at javase.paradigm.Point.main(Point.java:
60
)
|
错误信息已经很明显了,String类型不能转化成Integer类型。因此为了避免出现这种类型安全问题,我们就需要使用泛型
二 泛型的初步使用
(1)格式:
类名称<具体类> 对象名称 = new 类名称<具体类>()
如:Point2<Integer> point2_1 = new Point2<Integer>();
(2)完整测试案例代码如下:
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
|
package
javase.paradigm;
public
class
Point2<T> {
private
T var;
public
T getVar() {
return
var;
}
public
void
setVar(T var) {
this
.var = var;
}
public
static
void
main(String[] args) {
//1 整数
Point2<Integer> point2_1 =
new
Point2<Integer>();
point2_1.setVar(
20
);
System.out.println(
"整数测试:"
+ point2_1.getVar());
System.out.println(
"******************我是华丽的分割线**********************"
);
//字符串
Point2<String> point2_2 =
new
Point2<String>();
point2_2.setVar(
"zifangsky的个人博客"
);
System.out.println(
"字符串测试:"
+ point2_2.getVar());
}
}
|
输出:
1
2
3
|
整数测试:
20
******************我是华丽的分割线**********************
字符串测试:zifangsky的个人博客
|
将第一个例子修改成泛型:
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
41
42
43
44
45
46
|
package
javase.paradigm;
public
class
Point3<T> {
private
T x;
private
T y;
public
T getX() {
return
x;
}
public
void
setX(T x) {
this
.x = x;
}
public
T getY() {
return
y;
}
public
void
setY(T y) {
this
.y = y;
}
public
static
void
main(String[] args) {
//1 整数表示
Point3<Integer> point3_1 =
new
Point3<Integer>();
point3_1.setX(
10
);
point3_1.setY(
20
);
int
x1 = point3_1.getX();
int
y1 = point3_1.getY();
System.out.println(
"整数表示,X坐标是:"
+ x1 +
",Y坐标是:"
+ y1);
System.out.println(
"******************我是华丽的分割线**********************"
);
//2 字符串表示
Point3<String> point3_2 =
new
Point3<String>();
point3_2.setX(
"东经 50度"
);
point3_2.setY(
"北纬 79度"
);
String x2 = point3_2.getX();
String y2 = point3_2.getY();
System.out.println(
"字符串表示,X坐标是:"
+ x2 +
",Y坐标是:"
+ y2);
}
}<span style=
"font-family:'sans serif', tahoma, verdana, helvetica;font-size:16px;line-height:1.5;"
></span>
|
三 一个类中定义多个泛型类型
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
|
package
javase.paradigm;
public
class
Nodepad<K, V> {
private
K key;
private
V value;
public
void
setKey(K key) {
this
.key = key;
}
public
void
setValue(V value) {
this
.value = value;
}
public
void
print(){
System.out.println(
"键:"
+ key +
",值:"
+ value);
}
public
static
void
main(String[] args) {
Nodepad<String, Integer> nodepad =
new
Nodepad<String, Integer>();
nodepad.setKey(
"zifangsky"
);
nodepad.setValue(
100
);
//测试
nodepad.print();
}
}
|
输出:
1
|
键:zifangsky,值:
100
|
四 泛型方法的使用
(1)格式:
[访问权限]<泛型标志> 泛型标志 方法名称([泛型标志 参数名称])
(2)测试代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
package
javase.paradigm;
public
class
MethodDemo {
public
<T> T getData(T t){
return
t;
}
public
void
print(){
System.out.println(
"zifangsky"
);
}
public
static
void
main(String[] args) {
MethodDemo methodDemo =
new
MethodDemo();
methodDemo.print();
int
i = methodDemo.getData(
10
);
System.out.println(
"int: "
+ i);
String str = methodDemo.getData(
"hello world"
);
System.out.println(
"String: "
+ str);
}
}
|
输出:
1
2
3
|
zifangsky
int
:
10
String: hello world
|
五 泛型接口的定义和两种实现方式
(1)泛型接口的定义:
1
2
3
4
5
|
package
javase.paradigm;
public
interface
Info<T> {
public
T getVar();
}
|
(2)接口的实现方式一:
在子类的定义上申明泛型类型:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
package
javase.paradigm;
public
class
InfoImpl_1<T>
implements
Info<T> {
private
T var;
public
InfoImpl_1(T var) {
this
.var = var;
}
public
T getVar() {
return
this
.var;
}
public
void
setVar(T var) {
this
.var = var;
}
}
|
(3)接口的实现方式二:
直接在接口中指定具体类型:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
package
javase.paradigm;
public
class
InfoImpl_2
implements
Info<String> {
private
String var;
public
InfoImpl_2(String var) {
this
.var = var;
}
public
String getVar() {
return
this
.var;
}
public
void
setVar(String var) {
this
.var = var;
}
}
|
六 一个综合实例
(1)简单分析:
这里设计了Person这个类,但是一个人可能有多种信息展示形式,比如说:个人基本信息(姓名,性别,年龄。。。),联系方式(电话,地址,邮编。。。)。因此在Person中的信息类型就可以考虑申明为泛型。接着设计了一个空接口:Message和它的两个子类:Contact和Introduction,分别表示:联系方式和基本信息。
在对Person进行定义的时候用了:class Person<T extends Message> ,这里的意思是这个泛型T只能是Message这个接口的子类,也就是说只能是我们先前定义的Contact和Introduction,避免了传递进来我们所不需要的其他信息
(2)实例代码:
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
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
|
package
javase.paradigm;
/**
* 定义标识接口
* */
interface
Message{
}
/**
* 第一个子类,联系方式
* */
class
Contact
implements
Message{
private
String address;
private
String telphone;
private
String zipcode;
public
Contact(String address, String telphone, String zipcode) {
this
.address = address;
this
.telphone = telphone;
this
.zipcode = zipcode;
}
/**
* 重写toString方法
* */
public
String toString(){
return
"联系方式:\n"
+
"\t|- 电话: "
+ telphone +
"\n"
+
"\t|- 地址: "
+ address +
"\n"
+
"\t|- 邮编: "
+ zipcode +
"\n"
;
}
}
/**
* 第二个子类,个人信息
* */
class
Introduction
implements
Message{
private
String name;
private
String sex;
private
int
age;
private
String job;
public
Introduction(String name, String sex,
int
age, String job) {
this
.name = name;
this
.sex = sex;
this
.age = age;
this
.job = job;
}
/**
* 重写toString方法
* */
public
String toString(){
return
"基本信息:\n"
+
"\t|- 姓名: "
+ name +
"\n"
+
"\t|- 性别: "
+ sex +
"\n"
+
"\t|- 年龄: "
+ age +
"\n"
+
"\t|- 工作: "
+ job +
"\n"
;
}
}
/**
* 定义泛型,并且T必须是Message这个接口的子类
* 避免了传递进来其他不需要的类型
* */
public
class
Person<T
extends
Message> {
private
T message;
public
Person(T message) {
this
.message = message;
}
public
String toString(){
return
message.toString();
}
public
static
void
main(String[] args) {
//1 将泛型实例化成Contact类型
Person<Contact> person_1 =
new
Person<Contact>(
new
Contact(
"http://www.zifangsky.cn"
,
"10086"
,
"1024"
));
System.out.println(person_1);
System.out.println(
"******************我是华丽的分割线**********************"
);
//2 将泛型实例化成Introduction类型
Person<Introduction> person_2 =
new
Person<Introduction>(
new
Introduction(
"zifangsky"
,
"男"
,
256
,
"程序猿"
));
System.out.println(person_2);
}
}
|
输出:
1
2
3
4
5
6
7
8
9
10
11
|
联系方式:
|- 电话:
10086
|- 地址: http:
//www.zifangsky.cn
|- 邮编:
1024
******************我是华丽的分割线**********************
基本信息:
|- 姓名: zifangsky
|- 性别: 男
|- 年龄:
256
|- 工作: 程序猿
|