ZB-036-02泛型的绑定

先看这样的代码

1
2
3
4
5
6
7
8
9
10
11
12
13
public static Integer max(Integer a , Integer b){
return a > b ? a : b;
}

public static Long max(Long a , Long b){
return a > b ? a : b;
}

public static Double max(Double a , Double b){
return a > b ? a : b;
}

// 很啰嗦很重复

有了泛型

1
2
3
4
5
6
7
8
9
10
11
// 第一步简化代码成这样
public static T max (T a, T b){
// 此时 泛型类型实际是 Object 因此 是不能用 > 或者 < 的
return a > b ? a : b;
}
// 第二步 你知道 Integer/Long/Double 都是 Number的子类型 它们都是实现了Comparable接口 因此是可以比较的

// 定义传递的泛型的一个约定 是 继承 Comparable 的因此可以 compareTo 的
public static <T extends Comparable> T max (T a, T b){
return a.compareTo(b) >= 0 ? a : b;
}

你可以这样

1
2
3
4
max(1.0,2.0); // 你传递的是 Double 因此返回是 Double
max(1,2); // 你传递的是 Integer 因此返回是 Integer
max(1L,2L); // 你传递的是 Long 因此返回是 Long
max("aaa","bbb"); // 你传递的是 String 因此返回是 String

让你疑惑的地方 max("aaa",1) 竟然通过了编译为什么?

  • 泛型的约束条件是 <T extends Comparable>
  • String/Integer 都是 Comparable 的实现类
1
2
3
4
5
6
7
public static <T extends Comparable> T max (T a, T b){
return a.compareTo(b) >= 0 ? a : b;
}


max("aaa",1)
// 等价于 max(Comparable,Comparable)

虽然能通过编译,但是运行会报错,在本文最后会解释

传递多个类型

1
2
3
public static <A extends Comparable,B extends Comparable,C extends Comparable> A max2 (A a,  B b, C c){
return null;
}

取第一个list第一个元素

1
2
3
4
5
6
7
public static String first(List<String> list){
return list.get(0);
}

public static Integer first(List<Integer> list){
return list.get(0);
}

使用泛型后

1
2
3
public static <T> T first(List<T> list){
return list.get(0);
}

泛型的绑定

  • ? extends要求泛型是某种类型及其子类型
  • ? super 要求泛型是某种类型及其父类型
  • Collections.sort

按照参数绑定

1
2
3
public static <T extends Comparable> T max (T a, T b){
return a.compareTo(b) >= 0 ? a : b;
}

按照返回值绑定

让一个方法的返回值根据接受者动态的去改变

1
2
3
4
5
6
7
8
9
10
11
12
13
public class Main {

public static void main(String[] args) {

String s = cast("");
Object o = cast(new Object());
Integer i = cast(1);
}

public static <T> T cast(Object obj){
return (T) obj;
}
}

? super xx

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
package com.loder.demo;

import java.util.*;

public class Main {

static class Animal{}

static class Cat extends Animal{}

public static <T> void sort(List<T> list, Comparator<? super T> c){
list.sort(c);
}

static class AnimalComparator implements Comparator<Animal>{

@Override
public int compare(Animal o1, Animal o2) {
return 0;
}
}

static class CatComparator implements Comparator<Cat>{

@Override
public int compare(Cat o1, Cat o2) {
return 0;
}
}

public static void main(String[] args) {
// List<T> list, Comparator<? super T> c
// 除了 Cat 还可以是 Cat 的父类型
sort(new ArrayList<Cat>(),new CatComparator());
sort(new ArrayList<Cat>(),new AnimalComparator());
}

}

翻车问题重现

max("aa",1) 通过编译,但是运行报错?

  • 通过编译时因为刚才说了 String/Integer都是 Comparable 的子类型
  • 报错是因为Comparable没有泛型参数 导致传入的是一个裸类型
1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class Main {

public static <T extends Comparable> T max (T a, T b){
return a.compareTo(b) >= 0 ? a : b;
}

public static void main(String[] args) {
max("aa",1);
}

}

// 报错
Exception in thread "main" java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.String

修改代码

1
2
3
4
5
6
public static <T extends Comparable<T>> T max (T a, T b){
return a.compareTo(b) >= 0 ? a : b;
}

// 此时 编译期就报错了
max("aa",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
public class Main {
// 这里有四个结构、功能非常相似的方法,请尝试将其泛型化,以简化代码
// 泛型化之后的方法签名应该如下所示:
// public static boolean inAscOrder(T a, T b, T c)
public static boolean inAscOrder1(int a, int b, int c) {
return a <= b && b <= c;
}

public static boolean inAscOrder2(long a, long b, long c) {
return a <= b && b <= c;
}

public static boolean inAscOrder3(double a, double b, double c) {
return a <= b && b <= c;
}

public static <T extends Comparable<T>> boolean inAscOrder(T a, T b, T c){
return a.compareTo(b) <= 0 && b.compareTo(c) <= 0;
}

public static void main(String[] args) {
System.out.println(inAscOrder1(1, 2, 3));
System.out.println(inAscOrder2(1L, 2L, 3L));
System.out.println(inAscOrder3(1d, 2d, 3d));

System.out.println(inAscOrder(1, 2, 3));
System.out.println(inAscOrder(1L, 2L, 3L));
System.out.println(inAscOrder(1d, 2d, 3d));
}
}

泛型化的二叉树

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
package com.github.hcsp.generics;

import java.util.ArrayList;
import java.util.List;

public class Main {
static class IntBinaryTreeNode {
int value;
IntBinaryTreeNode left;
IntBinaryTreeNode right;
}

static class StringBinaryTreeNode {
String value;
StringBinaryTreeNode left;
StringBinaryTreeNode right;
}

static class DoubleBinaryTreeNode {
double value;
DoubleBinaryTreeNode left;
DoubleBinaryTreeNode right;
}

// 你看,上面三种"二叉树节点"结构相似,内容重复,请将其泛型化,以节省代码
static class BinaryTreeNode<T> {
T value;
BinaryTreeNode<T> left;
BinaryTreeNode<T> right;
}

// 泛型化之后,请再编写一个算法,对二叉树进行中序遍历,返回中序遍历的结果
public static <T> List<T> inorderTraversal(BinaryTreeNode<T> root) {
ArrayList<T> list = new ArrayList<>();
collectValue(root, list);
return list;
}

private static <T> void collectValue(BinaryTreeNode<T> node, ArrayList<T> list) {
if (node == null) {
return;
}
// 中序遍历递归 先左 再root 最后右
collectValue(node.left, list);
list.add(node.value);
collectValue(node.right, list);
}
}