协变定义方法:
package scala
import java.util.Date
object 协变 {
def main(args: Array[String]): Unit = {
//初始化协变类
var stringcovariant = new covariant[String]
var anycovariant = new covariant[Any]
//调用协变定义方法
var str: covariant[String] = new covariant[String]
str.test1[Any](new Date())
str.test2[Any](new Date())
}
}
/**
* 定义一个协变类
* @tparam T
*/
class covariant[+T](){
/*
我们定义一个方法,如下方法会报错:
原因:根据里式替换原则:父类使用的地方,换成子类也一定适用
那我们来看:假设方法可以通过编译:
var any = new convariant[Any]
var string = new convariant[string]
any.test0(nostring) 可以使用
父类替换为子类
string.test0(nostring) 报错,因为子类只能传入string参数
所以下面无法通过编译
*/
/*
def test0(value:T): Unit ={
println(value)
}
*/
/*
那么我们如何定义方法呢?
刚才的原因我们大概知道了,因为不符合里式替换原则。因为子类的权限比父类更小了。那么我们需要
提升子类的权限,起码要满足父类的所有使用场景。这里我们可以对参数类型使用逆变,或者不变。来提升
子类的使用范围。[T]或者[U>:T](value:U),只要可以设置传入任意参数就可以。不能仅仅只能传入string
类型
所以:我们这里对于传入参数的修改之处叫做逆变点。因为此处有个逆变的操作
*/
//这里定义
def test1[T](value:T): Unit ={
println(value)
}
def test2[U>:T](value:U): Unit ={
println(value)
}
}
逆变定义方法:
package scala
object 逆变 {
def main(args: Array[String]): Unit = {
var objectcon = new controvariane[Object]
var strcon = new controvariane[String]
//逆变性质
strcon = objectcon
println(strcon.test1())
println(strcon.test2())
}
}
/**
* 定义一个逆变类
*/
class controvariane[-T]{
/*
当定义方法的返回类型是逆变T时:
方法定义如下会报错,我们来查看下为什么会报错?
如果下面代码可以通过编译:
var any = new controvarine[any]
var str = new controvaiane[string]
any.test 返回 any
str.test 返回 string
因为any是str的子类(按照逆变定义)
那么将str替换为any后,原来返回string类型,替换后返回any类型
对于程序来讲,明显是类型越来越不清晰了。越来约不具体了。反而是越来
越抽象了。所以此时不符合里式替换原则。
*/
/*
def test():T={
null.asInstanceOf[T]
}
*/
/*
如下定义为什么不会出错呢,因为我们将返回类型设置为协变了。
也就是说,如果还是按照any和str举例。我们此时的any可以选择更
清晰,更具体的类了。也就是将范围扩大了。可以用来完全替换父类的
使用范围。所以编译又通过了。
*/
def test1[T]():T={
null.asInstanceOf[T]
}
def test2[U<:T]():U={
null.asInstanceOf[U]
}
}
留言:给大家留个思考空间哈,为什么在协变类中可以定义返回值是协变类型T的方法?为什么在逆变类中可以定义参数类型的时候可以不需要转化为协变或者不变呢?