Scala提供了Java所不具有的隐式转换和隐式参数功能,可以允许你手动指定,将某种类型的对象转换为其他类型的对象。在Spark中有大量的隐式转换和隐式参数。
Scala的隐式转换, 核心是定义隐式转换函数。 定义的隐式转换函数, 只要在编写的程序内引入, 就会被Scala自动使用。
Scala会根据隐式转换函数的签名, 在程序中使用到隐式转换函数接收的参数类型定义的对象时, 会自动将其传入隐式转换函数, 转换为另外一种类型的对象并返回。这就是“隐式转换” 。
隐式转换函数命名随意, 因为通常不会由用户手动调用, 而是由Scala进行调用。 但是如果要使用隐式转换, 则需要对隐式转换函数进行导入。 因此通常建议将隐式转换函数的名称命名为“one2one” 的形式。
隐式转换:
* 是scala中的一种特殊功能,它能将一种数据类型A转换成另外一种数据类型B,然后数据类型A就可以拥有数据类型B的所有方法,可以看成是对类的一种增强
* 隐式转换分为两种:
* 1,隐式转换函数
* 2,隐式转换值
* 定义隐式转换的关键字:implicit
* 隐式转换的命名方式是:one2one
class SpecialPerson(var name: String)
class Older(var name: String)
class Teacher(var name: String)
class Student(var name: String)
object ImplicitDemo01 {
def buySpecialTic(p: SpecialPerson) = {
if (p != null) println(p.name + "-购买了一张特殊票") else println("请购买常人票")
}
//定义隐式转换函数,将老人、老师转换为特殊人群类
implicit def any2SpecialPerson(any:Any):SpecialPerson = {
if(any.isInstanceOf[Older]) {
val older = any.asInstanceOf[Older]
new SpecialPerson(older.name)
}else if (any.isInstanceOf[Teacher]) {
val teacher = any.asInstanceOf[Teacher]
new SpecialPerson(teacher.name)
}else {
null
}
}
def main(args: Array[String]): Unit = {
val older = new Older("老人")
val tc = new Teacher("老师")
val stu = new Student("学生")
buySpecialTic(older)
buySpecialTic(tc)
buySpecialTic(stu)
}
}
实质是对类的增强!
class RichFile(var file: File) {
def read() = {
val context = Source.fromFile(file).mkString
println(context)
}
}
object ImplicitDemo02 {
def main(args: Array[String]): Unit = {
//将File类转换成RichFile类,以便可以调用RichFile类中的方法,实际上是对File类的增强
implicit def file2RichFile(file: File): RichFile = new RichFile(file)
val f1 = new File("C:\\Users\\root\\Desktop\\hello.txt")
f1.read
}
}
隐式参数:
* 在方法中,被implicit修饰的参数,称为隐式参数
* 隐式参数分为两种:
* 1,隐式转换函数
* 2,隐式转换值
class SingPen {
def write(context: String) = println(context)
}
object ImplicitDemo03 {
//pen 作为方法的参数,被implicit修饰,成为隐式参数。在调用方法时,该隐式参数可以自动引用。
def singForExam(name: String)(implicit pen: SingPen) = {
pen.write(name)
}
def main(args: Array[String]): Unit = {
//声明隐式转换值
implicit val singPen = new SingPen
//每个人签到是都要调用singPen,scala会自动调用
singForExam("张三")
singForExam("李四")
singForExam("王五")
}
}
隐式转换实现二次 排序-ordered & ordering
对象之间进行大小比较,或者排序,需要具备比较大小的功能
具备比较大小的功能有两种方法:
1,继承:继承Comparable接口,实现comparaTo方法,但是这种方法有一定的局限性,这种局限性就是将比较规则写死,后续进行调整,会影响之前的比较
2,隐式转换
可以很好的解决继承带来的局限性,比较规则不写在类中,而是以隐式转换的形式存在
trait Ordered[A] extends Any with java.lang.Comparable[A] 中有用于比较大小的抽象方法 def compare(that: A): Int
trait Ordering[T] extends Comparator[T] with PartialOrdering[T] with Serializable 中有用于比较大小的抽象方法 def compare(x: T, y: T): Int
//方法一:继承
class Girl(var name: String, var age: Int, var faceValue: Int) extends Comparable[Girl] {
override def compareTo(that: Girl): Int = {
if (this.age - that.age != 0) this.age - that.age
else if (this.faceValue - that.faceValue != 0) {
this.faceValue - that.faceValue
} else this.name.compareTo(that.name)
}
override def toString = s"Girl(name=$name,age = $age,faceValue = $faceValue)"
}
//方法二:隐式转换,将比较器放在类外
class Boy(var name: String, var age: Int, var faceValue: Int) {
override def toString = s"Boy(name=$name,age = $age,faceValue = $faceValue)"
}
//比较器
class Compare[T] {
//比较方法,第二个参数是隐式转换函数,目的是将T类型转换为Ordered类型,以便可以使用大小比较的方法
def compareTo(b1: T, b2: T)(implicit x: T => Ordered[T]): T = {
if (b1 >= b2) b1 else b2
}
//比较方法,第二个参数是隐式转换值,目的是将T类型转换为Ordering类型,以便可以使用大小比较的方法
def compareTo2(b1: T, b2: T)(implicit ord2: Ordering[T]): T = {
if (ord2.gteq(b1, b2)) b1 else b2
}
}
object ImplicitDemo04 {
def main(args: Array[String]): Unit = {
//隐式转换函数
implicit def boy2Ordered(b: Boy): Ordered[Boy] = new Ordered[Boy] {
override def compare(that: Boy): Int = {
if (b.age - that.age != 0) b.age - that.age
else if (b.faceValue - that.faceValue != 0) {
b.faceValue - that.faceValue
} else b.name.compareTo(that.name)
}
}
val b1 = new Boy("小明", 18, 90)
val b2 = new Boy("小王", 16, 95)
val cp1 = new Compare[Boy]
val resp = cp1.compareTo(b1, b2)
println(resp)
//隐式转换值
implicit val ord2: Ordering[Boy] = new Ordering[Boy] {
def compare(a: Boy, b: Boy): Int = {
if (a.age - b.age != 0) a.age - b.age
else if (a.faceValue - b.faceValue != 0) {
a.faceValue - b.faceValue
} else a.name.compareTo(b.name)
}
}
val b4 = new Boy("小明", 18, 90)
val b5 = new Boy("小王", 16, 95)
val c3 = new Compare[Boy]
val resB = c3.compareTo2(b4, b5)
println(resB)
}
}
扩大隐式转换的作用域
* 我们可以将隐式转换函数或隐式转换值定义在一个object对象中,来扩大隐式转换的作用域。
* 以后在其他地方使用的时候,直接import对应的隐式转换函数或隐式转换值
* 【注意】隐式转换函数或值只能定义在object对象中
object MyPredef {
implicit def any2SpecialPerson(any: Any): SpecialPerson = {
if (any.isInstanceOf[Older]) {
val older = any.asInstanceOf[Older]
new SpecialPerson(older.name)
} else if (any.isInstanceOf[Teacher]) {
val teacher = any.asInstanceOf[Teacher]
new SpecialPerson(teacher.name)
} else {
null
}
}
implicit def file2RichFile(file: File): RichFile = new RichFile(file)
implicit val singPen = new SingPen
implicit def boy2Ordered(b: Boy): Ordered[Boy] = new Ordered[Boy] {
override def compare(that: Boy): Int = {
if (b.age - that.age != 0) b.age - that.age
else if (b.faceValue - that.faceValue != 0) {
b.faceValue - that.faceValue
} else b.name.compareTo(that.name)
}
}
implicit val ord2: Ordering[Boy] = new Ordering[Boy] {
def compare(a: Boy, b: Boy): Int = {
if (a.age - b.age != 0) a.age - b.age
else if (a.faceValue - b.faceValue != 0) {
a.faceValue - b.faceValue
} else a.name.compareTo(b.name)
}
}
}
使用时,直接import即可。
import MyPredef.any2SpecialPerson //直接导入隐式转换函数
class SpecialPerson(var name: String)
class Older(var name: String)
class Teacher(var name: String)
class Student(var name: String)
object ImplicitDemo01 {
def buySpecialTic(p: SpecialPerson) = {
if (p != null) println(p.name + "-购买了一张特殊票") else println("请购买常人票")
}
def main(args: Array[String]): Unit = {
val older = new Older("老人")
val tc = new Teacher("老师")
val stu = new Student("学生")
buySpecialTic(older)
buySpecialTic(tc)
buySpecialTic(stu)
}
}
import MyPredef.file2RichFile//直接导入对应的隐式转换值
class RichFile(var file: File) {
def read() = {
val context = Source.fromFile(file).mkString
println(context)
}
}
object ImplicitDemo02 {
def main(args: Array[String]): Unit = {
val f1 = new File("C:\\Users\\root\\Desktop\\hello.txt")
f1.read
}
}
import MyPredef.singPen //直接导入隐式转换值
class SingPen {
def write(context: String) = println(context)
}
object ImplicitDemo03 {
def singForExam(name: String)(implicit pen: SingPen) = {
pen.write(name)
}
def main(args: Array[String]): Unit = {
//scala会自动调用
singForExam("张三")
singForExam("李四")
singForExam("王五")
}
}
import MyPredef.ord2
import MyPredef.boy2Ordered
//方法一:继承
class Girl(var name: String, var age: Int, var faceValue: Int) extends Comparable[Girl] {
override def compareTo(that: Girl): Int = {
if (this.age - that.age != 0) this.age - that.age
else if (this.faceValue - that.faceValue != 0) {
this.faceValue - that.faceValue
} else this.name.compareTo(that.name)
}
override def toString = s"Girl(name=$name,age = $age,faceValue = $faceValue)"
}
//方法二:隐式转换,将比较器放在类外
class Boy(var name: String, var age: Int, var faceValue: Int) {
override def toString = s"Boy(name=$name,age = $age,faceValue = $faceValue)"
}
//比较器
class Compare[T] {
//比较方法,第二个参数是隐式转换函数,目的是将T类型转换为Ordered类型,以便可以使用大小比较的方法
def compareTo(b1: T, b2: T)(implicit x: T => Ordered[T]): T = {
if (b1 >= b2) b1 else b2
}
//比较方法,第二个参数是隐式转换值,目的是将T类型转换为Ordering类型,以便可以使用大小比较的方法
def compareTo2(b1: T, b2: T)(implicit ord2: Ordering[T]): T = {
if (ord2.gteq(b1, b2)) b1 else b2
}
}
object ImplicitDemo04 {
def main(args: Array[String]): Unit = {
val b1 = new Boy("小明", 18, 90)
val b2 = new Boy("小王", 16, 95)
val cp1 = new Compare[Boy]
val resp = cp1.compareTo(b1, b2)
println(resp)
val b4 = new Boy("小明", 18, 90)
val b5 = new Boy("小王", 16, 95)
val c3 = new Compare[Boy]
val resB = c3.compareTo2(b4, b5)
println(resB)
}
}
视图界定
如:T <% Person
T 只能是Person类及其子类,或者T能隐式转换成Person类
class Person05(var name: String) {
def sayHello = println(s"hello,i am $name")
def mkFriends(p: Person05) = {
sayHello
p.sayHello
}
}
class Student05(name: String) extends Person05(name)
class Cat(var name: String) {
def say = println("喵喵喵...")
}
//视图界定:T <% Person,T 只能是Person类及其子类,或者T能隐式转换成Person类
class Party[T <% Person05](p1: T, p2: T) {
p1.mkFriends(p2)
}
object ImplicitDemo05 {
def main(args: Array[String]): Unit = {
//Person05对象
val p1 = new Person05("张三")
val p2 = new Person05("李四")
val pt = new Party[Person05](p1, p2)
//Student05对象
val s1 = new Student05("张三")
val s2 = new Student05("李四")
val pt2 = new Party[Student05](s1, s2)
implicit def cat2Person05(c: Cat): Person05 = new Person05(c.name)
//Cat对象
val c1 = new Cat("张三")
val c2 = new Cat("李四")
val pt3 = new Party[Cat](c1, c2)
}
}