一、隐式转换
隐式转换分为隐式函数、隐式参数、隐式类。
隐式转换就是编译器在第一次编译出错时,自己进行二次编译,找到可以正确编译的方法,从而实现功能
- 首先,编译器会在脚本的当前作用域范围内寻找并调用可以实现目标功能的转换规则(隐式函数/隐式类)
- 其次,若在当前作用域没找到隐式类/隐式函数,就会在隐式参数对应的类型的作用域中查找并调用可用的转换规则
隐式函数
隐式函数可以扩展某个类的功能,编译器会在当前作用域内寻找并调用实现目标功能的转换规则,从而自己进行二次编译,实现隐式转换
object Main {
def main(args:Array[String]):Unit=
{
//把包含目标方法的类定义为隐式函数,通过隐式函数扩展类的方法
implicit def Covert(i:Int):MyRichInt = new MyRichInt(i)
//直接调用隐式函数中的方法
println(12.myMax(13))
println(12.myMin(13))
}
}
//新建类
class MyRichInt(val i:Int){
def myMax(j:Int):Int = if (i>j) i else j
def myMin(j:Int):Int = if (i<j) i else j
}
13
12
隐式类
隐式类只能包含一个构造参数,隐式类的功能可以直接被调用。但是隐式类必须包含在包/对象/类中,不能独立放置。
object Main {
def main(args:Array[String]):Unit=
{
//新建隐式类
implicit class MyRichInt(val i:Int){
def myMax(j:Int):Int = if (i>j) i else j
def myMin(j:Int):Int = if (i<j) i else j
}
//直接调用隐式类中的方法
println(12.myMax(11))
println(12.myMin(11))
}
}
12
11
隐式参数
定义隐式参数后,调用方法时就不需要输入参数了,编译器会自己去获取并调用相同类型的隐式参数。
- 编译器在调用隐式参数时,是按照参数类型选取的,而不是参数名
- 隐式参数的名称与目标方法的参数类型必须一样,参数名可以不一样
- 相同类型的隐式参数在当前作用域内只能有一个,否则方法调用时不知道要用哪一个隐式参数
- 隐式参数放在方法最后的参数段:def 方法(一般参数)(implicit 隐式参数)
单个隐式参数:def 方法(parameter3,parameter4,…)(implicit parameter1:type)
object Main{
def main(args:Array[String]):Unit={
//新建隐式参数
implicit val str:String = "cindy"
implicit val age:Int = 18
//新建方法
def test(j:Int)(implicit i:String)={
println("hello," + j + "岁的" + i)
}
test(18) //相当于test(18)(),因为隐式参数可省略,所以()也可省略
}
}
hello,18岁的cindy
多个隐式参数:def 方法(parameter3,parameter4,…)(implicit parameter1:type,parameter2:type)
object Main{
def main(args:Array[String]):Unit={
//新建隐式参数
implicit val str:String = "cindy"
implicit val age:Int = 19
//新建方法
def test(m:String)(implicit j:Int,i:String)={
println(m + "," + j + "岁的" + i)
}
test("hello")
}
}
hello,19岁的cindy
简写:方法中的隐式参数可不写,直接用空括号,在方法体中用 implicitly[type] 来表示,因为隐式参数是通过类型来查找并调用的,名称可以没有
object Main{
def main(args:Array[String]):Unit={
//新建隐式参数
implicit val str:String = "cindy"
implicit val age:Int = 20
//新建方法
def test(m:String)()={
println(m + "," + implicitly[Int] + "岁的" + implicitly[String])
}
test("hello")
}
}
hello,20岁的cindy
二、泛型
泛型就是一种类型中元素的类型的统称,为方便为同一类型统一设定元素类型,就可以用泛型来定义
定义方式A[T],即A类型中所有元素都是T泛型
泛型的协变与逆变
协变:A[+T],类型A的之间的继承方向与泛型T之间的继承方向与一致,如A[子类]是A[父类]的子类
逆变:A[-T],类型A的之间的继承方向与泛型T之间的继承方向与相反,如A[子类]是A[父类]的父类
不变:A[T],即使泛型T之间有继承关系,类型A之间也无继承关系,如A[子类]与A[父类]无继承关系
object Main extends App {
val listParent: MyCollection[Parent] = new MyCollection[Parent] //对象与变量类型的泛型保持一致
val listChild: MyCollection1[Child] = new MyCollection1[SubChild] //对象类型的泛型是变量类型泛型的子类,则对象类型是变量类型的子类
val listSubChild: MyCollection2[SubChild] = new MyCollection2[Child] //对象类型的泛型是变量类型泛型的父类,则对象类型是变量类型的子类()
println(listParent.getClass.getName)
println(listChild.getClass.getName)
println(listSubChild.getClass.getName)
}
//定义继承类
class Parent{}
class Child extends Parent{}
class SubChild extends Child{}
//定义带泛型的集合类型
class MyCollection[e]{} //不变
class MyCollection1[+e]{} //协变
class MyCollection2[-e]{} //逆变
MyCollection
MyCollection1
MyCollection2
泛型上下限
即对泛型进行限定
- 上限A[T <: type]:类型A的泛型T只能是type类型或其子类型
- 下限A[T >: type]:类型A的泛型只能是type类型或其父类型
object Main extends App {
//上下限与协变结合
val listParent: MyCollection[Parent] = new MyCollection[Parent]
val listChild: MyCollection[Parent] = new MyCollection[Child] //泛型为下限Child,且MyCollection[Child]为MyCollection[Parent]的子类
val listSubChild: MyCollection1[Child] = new MyCollection1[SubChild] //泛型上限为Child,且MyCollection1[SubChild]为MyCollection1[Child]的子类
val listSubChild1: MyCollection1[Child] = new MyCollection1[Child]
println("上下限与协变结合的结果:")
println(listParent.getClass.getName)
println(listChild.getClass.getName)
println(listSubChild.getClass.getName)
println(listSubChild1.getClass.getName)
println("上下限的结果:")
//上下限
def test[A <: Child](i:A)={
println(i.getClass.getName)
}
test[Child](new Child)
test[SubChild](new SubChild)
test[Child](new SubChild)
//test[SubChile](new Child) 这种不行,因为参数的类型只能是函数的泛型或其子类
}
//定义继承类
class Parent{}
class Child extends Parent{}
class SubChild extends Child{}
//定义带泛型的集合类型
class MyCollection[+e>:Child]{} //泛型上限
class MyCollection1[+e<:Child]{} //泛型下限
上下限与协变结合的结果:
MyCollection
MyCollection
MyCollection1
MyCollection1
上下限的结果:
Child
SubChild
SubChild