隐式转换
隐式转换函数是以implicit关键字声明的带有单个参数的函数。这种函数将会自动应用,将值从一种类型转换为另一种类型
PS:使用隐式函数可以优雅的解决数据类型转换
案例
将double类型和字符串类型数据转换成Int类型
package com.example
object Main {
implicit def double2Int(d: Double): Int = {
println("execute Double to Int.................." + d)
d.toInt
}
implicit def long2Int(d: Long): Int = {
println("execute Long to Int.................." + d)
d.toInt + 13
}
implicit def string2Int(d: String): Int = {
println("execute String to Int.................." + d)
d.length
}
def main(args: Array[String]): Unit = {
val num1: Int = 3.5
println("Double to Int: " + num1)
val num2: Int = 20L
println("Long to Int: " + num2)
val s1: Int = "aa"
println("String to Int: " + s1)
val s2: Int = "abc"
println("String to Int: " + s2)
}
}
执行结果
//Double、Long、String 是输入类型, Int 是转换后的类型
execute Double to Int..................3.5
Double to Int: 3
execute Long to Int..................20
Long to Int: 33
execute String to Int..................aa
String to Int: 2
execute String to Int..................abc
String to Int: 3
总结
相当于执行前会调用这个隐式转换函数
注意事项
- 隐式转换函数的函数名可以是任意的,隐式转换与函数名称无关,只与函数签名(函数参数类型和返回值类型)有关
- 隐式函数可以有多个(即:隐式函数列表),但是需要保证在当前环境下,只有一个隐式函数能被识别(如果被识别出来有多个方法可被调用,会因为不确定调用哪个方法而报错)
- 隐式操作不能嵌套使用
隐式转换的好处
隐式转换可动态的增加功能,比如,现在Human已经具备了说话的能力,如果想要赋予它唱歌的能力的话,改动源码是很难接受的(如果是三方的程序就更难改动),而且也违背了软件开发的OCP开发原则 (开闭原则 open close priceple) ,可以通过隐式转换函数给类动态添加功能
package com.example
object StrongObject {
// 将human对象变成women对象,增强human对象的功能
implicit def strongObject(h: Human): Women = {
println("execute Human to Women..................")
new Women
}
def main(args: Array[String]): Unit = {
val human = new Human
human.speak("努力努力再努力")
human.sing("情书")
}
class Human {
def speak(content: String): Unit = {
println("人类说话:" + content)
}
}
class Women {
def sing(content: String): Unit = {
println("女士唱歌:" + content)
}
}
}
执行结果
人类说话:努力努力再努力
execute Human to Women..................
女士唱歌:情书
隐式参数
将某个形参变量标记为implicit,所以编译器会在方法省略隐式参数的情况下去搜索作用域内的隐式值作为缺省参数
案例
package com.example
object ImplicitParam {
implicit val str: String = "华晨宇"
def hello(implicit name: String): Unit = {
println("hello: " + name)
}
def main(args: Array[String]): Unit = {
//如果找到值就去对应的作用域内找隐式参数值
hello
//有值的话就使用入参中的值
hello("关晓彤")
}
}
执行结果
hello: 华晨宇
hello: 关晓彤
隐式类
在scala2.10后提供了隐式类,可以使用implicit声明类,隐式类的非常强大,同样可以扩展类的功能,比前面使用隐式转换丰富类库功能更加的方便,在集合中隐式类会发挥重要的作用
package com.example
object ImplicitClass {
def main(args: Array[String]): Unit = {
implicit class Women(val h: Human) {
def sing(content: String): Unit = {
println("女士唱歌:" + content)
}
}
val human = new Human
human.speak("努力努力在努力")
human.sing("情书")
}
class Human {
def speak(content: String): Unit = {
println("人类说话:" + content)
}
}
}
执行结果
人类说话:努力努力在努力
女士唱歌:情书
隐式类特点
- 其所带的构造参数有且只能有一个
- 隐式类必须被定义在“类”或“伴生对象”或“包对象”里,即隐式类不能是 顶级的(top-level objects)。
- 隐式类不能是case class
- 作用域内不能有与之相同名称的标识符
隐式转换的发生时机
- 当方法中的参数的类型与目标类型不一致时
- 当对象调用所在类中不存在的方法或成员时,编译器会自动将对象进行隐式转换(根据类型)