啥是隐式转换?
我们需要某个类中的一个方法,但是这个类没有提供这样的一个方法,所以我们需要隐式转换,转换为提供了该方法的类后,该类则变为了原来的类的增强类。某个类+该类不具备的方法->增强类。
举个例子:一个普通人people拥有吃饭、睡觉等基本方法,当people这种普通人有一天想要变成一位猛男时,按照我们之前的思路则应该为这个普通人添加一个muscleMan的方法或者去继承猛男类来获得猛男的方法。但这种实现方式针对有些特殊场景并不适用,如:
- 1)如果猛男这个类是黑盒的,你如何去为普通人
people添加一个已有的猛男方法呢? - 2)如果你频繁的去使用继承的方式,是否又忽略了开发的原则。高内聚,低耦合?
所以在此引出implicit这个概念,下文将逐步带你领略implicit的魅力。
隐式转换的实现方式
- 1)将方法或类型标记为implicit
- 2)将类标记为implicit
- 3)将方法的参数列表标记为implicit(这个不常用)
将方法标记为implicit
Biliking由于是通过Pepole类new出来的对象,所以它只会吃喝,并不是个猛男
object Myimplicit {
def main(args: Array[String]): Unit = {
//比利王从前也是个普通人
val BiliKing = new People("比利王")
BiliKing.
}
}
class People(val name: String){
def eat():Unit = {
println(s"$name 吃饭了")
}
def sleep():Unit = {
println(s"$name 睡觉了")
}
}
我们现在需要通过隐式转换让比利得到成为猛男的方法
//把普通人放进去,返回一个SuperMan
implicit def peopleToSuperMan(people: People):SuperMan = {
new SuperMan(people.name)
}
最终代码:
object Myimplicit {
def main(args: Array[String]): Unit = {
//比利王从前也是个普通人
val BiliKing = new People("比利王")
//把普通人放进去,返回一个SuperMan
implicit def peopleToSuperMan(people: People):SuperMan = {
new SuperMan(people.name)
}
//通过隐式转换后,所有从Peope创建的对象都将拥有muscleMan()的方法,比利也从此变成了一个猛男
BiliKing.muscleMan()
}
}
class People(val name: String){
def eat():Unit = {
println(s"$name 吃饭了")
}
def sleep():Unit = {
println(s"$name 睡觉了")
}
}
class SuperMan(val name: String){
def muscleMan():Unit = {
println(s"$name 变成了个大猛男")
}
}
将类标记为implicit
object Myimplicit {
def main(args: Array[String]): Unit = {
//比利王从前也是个普通人
val BiliKing = new People("比利王")
BiliKing.muscleMan()
}
//通过隐式转换后,所有从Peope创建的对象都将拥有muscleMan()的方法,比利也从此变成了一个猛男
implicit class ChangeMuscleMan(people: People){
def muscleMan():Unit = {
println(s"${people.name} 变成了个大猛男")
}
}
}
class People(val name: String){
def eat():Unit = {
println(s"$name 吃饭了")
}
def sleep():Unit = {
println(s"$name 睡觉了")
}
}
将类型标记为implicit
以int类型为例,为所有int类型增强一个加减乘的方法aSM
object Myimplicit {
def main(args: Array[String]): Unit = {
1.aSM("add", 1)
10.aSM("sub", 1)
}
//定义一个隐式转换,类型为int
implicit class AddSubXAvg(x:Int){
//模式匹配
def aSM(input:String ,value:Long):Long = input match {
case "add" => x + value
case "sub" => x + value
case "X" => x + value
}
}
}
将方法的参数列表标记为implicit
默认情况下,这个参数是必填的,如果不填就会报错
object Myimplicit {
def main(args: Array[String]): Unit = {
val yy = new People("YY哥")
// yy.eat
implicit val lala = 2
yy.eat
}
}
class People(val name: String){
def eat(implicit eatHowMuch:Int):Unit = {
println(s"$name 吃饭了 吃了$eatHowMuch 大碗")
}
}
注意:如果出现多个
int被implicit,程序时反应不过来的。所以仅能有一个变量值被隐式转换
隐式转换的滥用问题
建议单独做一个隐式转换切面,所有的隐式转换都放在类中,如下所有隐式转换都在implicitGuiDang中。哪里需要用到时,请在需要使用的类中导入implicitGuiDang即可
object implicitGuiDang{
implicit class AddSubXAvg(x:Int){
//模式匹配
def aSM(input:String ,value:Long):Long = input match {
case "add" => x + value
case "sub" => x + value
case "X" => x + value
}
}
}
隐式转换的作用域问题
- 有些情况下,隐式转换需要提到代码块的最上面才可以
- 隐式转换可以定义在伴生对象中,隐式转换会去相关类的伴生对象中去找,例如:去pepole以及猛男类中找