0703-隐式转换
1. Scala 中的值类型转换
1.1 Scala值类型隐式转换
当Scala程序在进行赋值或者运算时,
精度小的类型自动转换为精度大
的类型.
- Byte ----> Short -----> Int ----> Long ----> Float ----> Double ----> AnyVal ----> Any
- Char ----> Int ----> Long ----> Float ----> Double ----> AnyVal ---- Any
自动类型转换细节说明
- 有多种类型的数据混合运算时, 系统首先自动将所有数据转成容量最大的那种数据类型, 然后进行计算
- 当我们吧精度(容量)大的数据类型赋值给精度小的数据类型式, 就会报错
- Byte, Short 和Char之间不会进行自动转换
Byte, Short, Char他们三者可以计算, 在计算时首先转为Int类型
- 自动提示原则: 表达式结果的类型自动提升为操作数中最大的类型
1.2 Scala多态语法中的类型自动转换
child->parent->trait(interface)
Parent p = new Child()
1.2 Scala高级隐式转换
scala 也允许开发人员自定义类型转换规则,将两个无关的类型通过编程手段让他们可以自动转换。
1.3 Scala值类型强制转换
自动类型转换的逆过程,将
容量大的数据类型转换为容量小
的数据类型。使用时要加上强制转函数,但可能造成精度降低或溢出,格外要注意。
// java
int num = (int)2.5;
// scala
var num : Int = 2.5.toInt
- 值类型和String类型的转换
// 基本类型转String
String str1 = true + ""
String str2 = 4.5 + ""
// String类型转基本数据类型
s1.toInt
s2.toFloat
// java
// 字符串转其他
String str = "323";
int i = Integer.parseInt(str);
Integer integer = Integer.valueOf(str);
float v = Float.parseFloat(str);
Float aFloat = Float.valueOf(str);
2. Scala 隐式转换
2.1 问题引入
隐式转换的引入是允许开发人员自定义类型转换规则,将两个无关的类型通过
编程手段让他们可以自动转换。
达到在满足OCP
开发原则的基础上,实现对动能的动态扩展
.
- Demo01
package com.lz.scala.day05
/**
* @ClassName Demo01TransformImplicit
* @Description: 隐式转换
* @Author MAlone
* @Date 2019/11/8
* @Version V1.0
**/
object Demo01TransformImplicit {
def main(args: Array[String]): Unit = {
implicit def transform(d: Double) = {
d.toInt
}
//当发现程序有误时,Scala编译器会尝试在隐式函数列表中查询可以进行转换的函数
val i: Int = 5.0
}
}
- Demo02
// 这是实现了具体的业务功能的类.
class Case01{
def plus(x: Int, y:Int) ={
x + y
}
}
// 调用 Case01的plus功能
object Demo {
def main(args: Array[String]): Unit = {
val c: Case01 = new Case01()
val result: Int = c.plus(1, 2)
}
}
但是, 如果现在需要 plus(“1”, “2”), 需要对Case01 中的plus功能做扩展, 当然要满足OCP原则, 原Case01 不能有一点修改.
- 解决方案一: 为Case01 动态添加plus String的功能
class Case02{
def plus(x: String, y:String)={
x + y
}
}
object Demo {
def main(args: Array[String]): Unit = {
val c: Case01 = new Case01()
val result: Int = c.plus(1, 2)
implicit def transformCase01ToCase02(c1 : Case01): Case02 ={
new Case02
}
val result2: String = c.plus("1", "2")
}
}
- 解决方案二: String2Int
object Demo {
def main(args: Array[String]): Unit = {
val c: Case01 = new Case01()
implicit def transformString2Int(str:String) : Int={
str.toInt
}
val result: Int = c.plus(1, 2)
val result2: Int = c.plus("1", "2")
}
}
2.2 利用隐式转换丰富类库功能
如果需要为一个类增加一个方法,可以通过隐式转换来实现。比如想为MySQL增加一个delete方法
class MySQL {
def insert( id : Int ): Unit = {
println("向数据库中插入数据:" + id)
}
}
var mysql = new MySQL()
mysql.insert(1)
// 在当前程序中,如果想要给MySQL类增加功能是非常简单的,但是在实际项目中,如果想要增加新的功能就会需要改变源代码,这是很难接受的。而且违背了软件开发的OCP开发原则
// 在这种情况下,可以通过隐式转换函数给类动态添加功能。
class DB {
def delete( id : Int ): Unit = {
println("从数据库中删除数据:" + id)
}
}
val mysql = new MySQL
implicit def addFun( db : MySQL ) : DB ={
new DB()
}
mysql.delete(1)
2.3 隐式值
将name变量标记为implicit,所以编译器会在方法省略隐式参数的情况下去搜索作用域内的隐式值作为缺少参数。
package com.lz.scala.day05
/**
* @ClassName Demo03TransformImplicit3
* @Description: 隐式参数
* @Author MAlone
* @Date 2019/11/8
* @Version V1.0
**/
object Demo03TransformImplicit3 {
def main(args: Array[String]): Unit = {
// 隐式值
implicit val username: String = "wangwu"
// 隐式参数
def test(implicit name: String = "zhangsan") = {
print(name)
}
// 三种调用方式
// 1.使用默认值,必须加括号
test()
// 2.改变默认值
test("wagnwu")
// 3.使用隐式值,不加括号,加括号会导致隐式值无法传递
test
}
}
2.4 隐式类
在scala2.10后提供了隐式类,可以使用implicit声明类,但是需要注意以下几点:
- 其所带的构造参数有且只能有一个
- 隐式类必须被定义在“类”或“伴生对象”或“包对象”里 3) 隐式类不能是case class(case class在后续介绍)
- 作用域内不能有与之相同名称的标示符
object StringUtils {
implicit class StringImprovement(val s : String){ //隐式类
def addSuffix = s + " Scala"
}
}
println("Hello". addSuffix)
2.5 隐式转换的时机
- 当方法中的参数的类型与目标类型不一致时
- 当对象调用所在类中不存在的方法或成员时,编译器会自动将对象进行隐式转换