[TOC]

一. 泛型介绍

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
package cn.ngp.demo;
//(generic)泛型避免了: 向下转型可能造成的安全隐患
//此时设置的T在Point类定义上只表示一个标记,在使用的时候需要为其设置具体的类型
class Point<T>{ //定义坐标, Type = T,是一个类型
private T x ; //此属性的类型不知道,由Point类使用时动态决定
private T y ;
public void setX(T x) {
this.x = x;
}
public T getX() {
return x;
}
public void setY(T y) {
this.y = y;
}
public T getY() {
return y;
}
}
public class TestDemo {
public static void main(String[] args) {
//第一步: 设置数据
// Point p = new Point<>();//JDK1.7之后,后一个方括号内的Integer可以省略,不过建议代码写得完善一些
Point p = new Point();// 如果没有增加,将使用Object类型描述泛型
p.setX(100);
p.setY(20);
// p.setX("东经100度"); // 如果设置的数据类型是错误的,那么在编译的时候就会自动的排查
// p.setY("北纬20度");
//第二步: 取出数据,由于接受的类型就是String,所以不需要向下强制编译
//利用了包装类的自动装箱功能
int x = (Integer)p.getX();
int y = (Integer)p.getY();
// String x = (String) p.getX();
// String y = (String) p.getY();
System.out.println("x坐标: " + x + " ,y坐标: " + y);
}
}

二. 通配符(<?extends 类>、<?super 类>)

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
package cn.ngp.demo;
class Message<T>{
private T msg;
public void setMsg(T msg) {
this.msg = msg;
}
public T getMsg() {
return msg;
}
}
public class TestDemo {
public static void main(String[] args) {
Message<Integer> m = new Message<Integer>();
m.setMsg(1);
// m.setMsg("Hello World!");//如果这里是字符串,就会提示错误,Eclipse的好处,在编译的时候提示错误
fun(m); //引用传递
}
//?extends 类: 设置泛型上限,可以再声明上和方法参数上使用;
// → ?extends Number:意味着可以设置Number或者是Number的子类(Integer、double、...)
//?super 类: 设置泛型下限;
// → ?super String:意味着只能够设置String或者是它的父类Object
public static void fun(Message<? extends Number> temp) { //?表示不能设置,但能够取出
System.out.println(temp.getMsg());
}
}

三. 泛型接口

  1. 子类也继续使用泛型,并且父类接口使用和子类相同的泛型
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
package cn.ngp.demo;
//如果是接口,在前面加上字母I,例如: IMessage
//如果是抽象类,在前面加上Abstract,例如:AbstractMessage
//如果是普通类,直接编写,例如:Message
interface IMessage<T>{
public void print(T t);
}
//子类也继续使用泛型,并且父类接口使用和子类相同的泛型
class MessageImpl<T> implements IMessage<T> {
public void print(T t) {
System.out.println(t);
}
}
public class TestDemo {
public static void main(String[] args) {
IMessage<String> msg = new MessageImpl<String>();
msg.print("Hello World!");
}
}

2.在子类不设置泛型,而为父接口明确定义一个泛型类型
>package cn.ngp.demo;
//如果是接口,在前面加上字母I,例如: IMessage
//如果是抽象类,在前面加上Abstract,例如:AbstractMessage
//如果是普通类,直接编写,例如:Message
interface IMessage<T>{
public void print(T t);
}
//在子类不设置泛型,而为父接口明确定义一个泛型类型
class MessageImpl implements IMessage<String> {
public void print(String t) {
System.out.println(t);
}
}
public class TestDemo {
public static void main(String[] args) {
IMessage<String> msg = new MessageImpl();
msg.print("Hello World!");
}
}

四. 泛型方法

泛型方法不一定要定义在支持泛型的类里面。
一 → 四 所有存在有泛型的方法,都是在支持泛型的类里面定义的。

1
2
3
4
5
6
7
8
9
10
11
package cn.ngp.demo;
public class TestDemo {
public static void main(String[] args) {
String str = fun("Hello");
System.out.println(str.length());
}
//T的类型由传入的参数类型决定
public static <T> T fun (T t) {
return t;
}
}

五. 总结

  • 泛型解决的是向下转型所带来的安全隐患,其核心的组成就是在声明类或接口的时候不设置参数或者属性的类型
  • "?"可以接受任意的泛型类型,只能够去除,但是不能够修改

参考

来自: 阿里云大学(笔记) → 零基础学Java10系列三:Java高级编程