Java泛型

Java泛型

【摘要】Java泛型~

前言

在JDK5.0之前,没有泛型,那时的集合类本质上是以Object为泛型,因为这样可以存放任意对象。
如:

1
2
3
4
5
6
List a = new ArrayList();
a.add(123); //ok
a.add("jack"); //ok
a.add(new Book(...)); //ok
//迭代a集合
//...

可见,在没有泛型的年代,集合在使用时,程序员要“主动”遵守约定,就是一个集合只存放一种类型。
现在,JDK5.0开始,引入了泛型,它的目的就是让这些“容器”类能够事先约定好它将要存放什么类型的数据。并且JVM负责检查。
如:

1
2
3
List<String> b = new ArrayList<>(); //jdk7.0后,后面的泛型类型可以省略
b.add(123); //compile error, 因为集合b只能存放 String类型的对象
b.add("jack"); //ok

泛型 [Generic Type]

所谓泛型,就是 类型参数化[type parameterize]。也就是把类型当参传一样的传递。
它的语法:

1
类型<泛型字母>

在JDK5.0中,整个JCF都全部采用泛型的语法重写过。
如:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
//jdk1.5之前的集合类
public class ArrayList {
public boolean add(Object e) { ... }
//...
}
//JDK5.0之后的集合类
public class ArrayList<E> { //泛型类
public boolean add(E e) { /*...*/ }
//...
//...
}
//so
List<Book> bList = new ArrayList<>();
List<Integer> iList = new ArrayList<>();
Map<String,Book> map = new HashMap<>();
//...
Set<Entry<Integer,Book>> set = ...;

思考?是不是所有类型都要定义成泛型类?
当然不是,如:

1
2
3
4
5
6
public class Student {
private Integer id;
private String name;
private int age;
//...
}

只有需要把类型当做参数传递的类型定义时才需要泛型。

如何使用泛型类?

如何自定义泛型类?

如:

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
public class Entry {
private Object key;
private Object value;
//构造
//...
//get/set
public Object getKey() { return this.key; }
//...
public void setValue(Object obj) { this.value = obj; }
//...
}
//使用它
Entry e1 = new Entry(123,"Spring");
Entry e2 = new Entry("Jack",18L);

//如果改写成泛型类
public class Entry<K, V> {
private K key;
private V value;
//构造
//...
//get/set
public K getKey() { return this.key; }
//...
public void setValue(V obj) { this.value = obj; }
//...
}
//使用它
Entry<Integer,String> e1 = new Entry<>(123,"Spring");
Entry<String, Long> e2 = new Entry<>("Jack",18L);

泛型仅仅是编译期间的概念,在运行时是没有泛型的。泛型是不存在多态性的。

如:

1
2
3
4
Number n = new Integer(100); //ok
List b = new ArrayList(); //ok
//
List<Number> bn = new ArrayList<Integer>(); // compile error

注:泛型是不存在多态性的

所以,上面这条语句是错误的。

1
List<Number> bn = new ArrayList<>();  //ok

再看:

1
2
3
4
List<Number> bn1 = new ArrayList<>(); //ok
List<Integer> bn2 = new ArrayList<>(); //ok
//
bn1 = bn2;

泛型的通配符

? 可以通配任意类型
? extends 类型 来限定通配[?所代表的类型比后面的类型要小或一样]
? super 类型 来限定通配[?所代表的类型比后面的类型要大或一样]

如:

1
2
3
4
5
6
7
8
List<?> a = new ArrayList<Integer>(); //ok, 泛型没有确定
//所以,这个集合a不能存放任何有效数据,除 null 外
a.add(null); //ok
a.dd(100); //error

List<Long> b = new ArrayList<>();
//
a = b; //ok

自定义泛型方法

就是指所在的类本身不是泛型类,而这个类的方法要定义成泛型方法。
语法:

1
2
3
修饰符 <T> 返回类型 方法名(参数列表) throws 异常 {
//方法体
}

在 修饰符 和 返回类型之间,使用 定义好泛型字母,然后,在方法的参数或方法体中就可以使用这个泛型字母。

如:

1
2
3
4
5
6
public class Demo {
public static <T> void ma(T o) {
//
//...
}
}

例:定义一个泛型方法,找到两个对象的中的最大值。

1
2
3
4
5
public class Demo {
public static <T extends Comparable<T>> T max(T a, T b) {
//...
}
}

结束语

bye~

评论