本节主要内容
- 类型变量界定(Type Variable Bound)
- 视图界定(View Bound)
- 上界(Upper Bound)与下界(Lower Bound)
1. 类型变量界定(Type Variable Bound)
类型变量界定是指在泛型的基础上,对泛型的范围进行进一步的界定,从而缩下泛型的具体范围,例如:
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
如果在使TypeVariableBound类编译通过,此时可以利用类型变量界定对泛型T进行界定,指明所有的泛型T都实现了Comparable接口,代码如下:
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
从上述代码可以看到,compare方法中如果输入的类型处于Comparable类对应继承层次结构中,则是合法的,否则的话编译会报错,例如:
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
如果需要输入Person类也合法的话,则Person类要实现Comparable接口,代码如下:
- 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
- 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
上面的类型变量界定都是作用于方法Compare上,类型变量界定除了作用于方法上外,还可以对类中的泛型进行范围限定,例如:
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
从上面的例子中不难看出,类型变量界定可以对方法和类中的泛型进行范围界定,这种界定建立在类继承层次结构的基础之上,通过<:符号将泛型的范围进行一步减少。
2. 视图界定(View Bound)
上一节将的类型变量界定建立在类继承层次结构的基础上,但有时候这种限定不能满足实际要求,如果希望跨越类继承层次结构时,可以使用视图界定来实现的,其后面的原理是通过隐式转换(我们在下一讲中会详细讲解什么是隐式转换)来实现。视图界定利用<%符号来实现,在上一节中提到:
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
上面这个问题可以通过视图界定来解决,代码如下:
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
查看Scala API文档可以看到
Int类会隐式转换成RichInt类,RichInt并不是直接实现Comparable口,而是通过ScalaNumberProxy类将Comparable中的方法继承过来:
ScalaNumberProxy混入了OrderedProxy,而OrderedProxy又混入了Ordered
trait Ordered混入了Comparable接口
可以看到,视图界定比类型变量界定的限制要宽松一点,它不但可以是类继承层次结构中的类,也可以跨越类继承层次结构,这后台的实现方式是通过隐式转换来进行的。
3. 上界(Upper Bound)与下界(Lower Bound)
下类代码其实是类型参数中经常提到的上界,这是因为它限定了继承层次结构中最顶层的类,例如T <: AnyVal表示泛型T的类型的最顶层类是AnyVal,所有输入是AnyVal的子类都是合法的,其它的都是非法的,因为被称为上界,有点像x<=3这样的数学比较。
- 1
- 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
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 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
通过上述代码发现,如果newFirst的类型刚好是T的基类,R就直接是newFirst的类型。如果newFirst的类型不是T的基类,那R就会是T和newFirst的类型的共同基类。当限定返回变量类型时,例如val p6:Pbook=p4.replaceFirst(weirdFirst)
,由于p4为Pair1[Pbook],也即T为Pbook类型,而replaceFirst(weirdFirst)中的weirdFirst为Pbook的子类,违反了R>:T的下界限定,从而编译出错。从这里我们可以看到,下界的作用主要是保证类型安全