Scala面向对象编程-隐式转换

隐式转换

隐式转换就是自动类型转换。 如 var dbl:Double = 12 int 自动转换double, 但是 val num:Int =3.5 确会报错。我们可以自己通过定义隐式转换来实现 double自动转换Int

隐式转换函数

隐式转换函数是以implicit 关键字声明的带有单个参数的函数,这种函数会自动应用将值从一种类型转换为另一种类型
注意事项:
1)隐式转换的函数名可以是任意的,饮食转换与函数名无关,只和函数签名(参数类型和返回值类型)有关
2)隐式函数可以有多个,但是要保证在当前环境下只有一个隐式函数可以被识别,如果有多个函数都可以使用 那编译器就不知道要用哪个了
示例

def test: Unit ={
     var dbl:Double = 12 //可以自动实现类型转换
     implicit def f1(d:Double): Int ={//定义一个隐式转换函数 将Double类型转换为 Int 类型
       return d.intValue()
     }
     implicit def f2(d:Float): Int ={//定义一个隐式转换函数 将float类型转换为 Int 类型
       return d.intValue()
     }
//     implicit def f3(d:Float): Int ={//定义一个隐式转换函数 将float类型转换为 Int 类型
//       return d.intValue()           //因为f3 和 f2 签名相同 两个方法冲突 必须删除一个 否则 float隐式转换int时编译器不知道用哪个
//     }
      val num:Int =3.5//定义隐式转换函数后 这种写法不再报错
       var num2:Int =2.1f
   }

反编译底层实现

public final class class09$
{
  public static  MODULE$;

  static
  {
    new ();
  }

  public void test()
  {
    double dbl = 12.0D;

    int num = f1$1(3.5D);
    int num2 = f2$1(2.1F); }

  public void main(String[] args) {
    test();
  }

  private static final int f1$1(double d)
  {
    return Predef..MODULE$.double2Double(d).intValue(); }

  private static final int f2$1(float d) {
    return Predef..MODULE$.float2Float(d).intValue();
  }

  private class09$()
  {
    MODULE$ = this;
  }
}

隐式转换丰富类功能

隐式转换可以丰富类功能
示例

class MySQL{//类 Mysq可以执行insert 操作
    def insert(): Unit ={
       println("insert")
    }
  }

  class DB{//类 DB 可以执行delete 操作
    def delete(): Unit ={
      println("delete ~~~");
    }
  }
  def test: Unit ={
     //声明一个隐式函数,当在函数作用范围内创建一个 MySQL 并且实用 DB类中的方法时,可以自动转换为DB类
     implicit def addDelete(mysql:MySQL ): DB ={
       return new DB
     }
     var mysql = new MySQL
     mysql.insert()
     //因为有了上述隐式转换函数 mysql可以执行 DB类中的操作
     //编译器在编译时会调用隐式函数 addDelete 并得到一个DB对象 然后执行 db对象的 delete方法
     mysql.delete()
   }

反编译

     public void test()
  {
    class09.MySQL mysql = new class09.MySQL();
    mysql.insert();

    addDelete$1(mysql).delete(); }

隐式值

隐式值也叫做隐式变量,将某个形参变量标记为implicit后,如果调用方法时为传入参数,那么编译器会
搜索作用域内对应的隐式值作为缺省参数
注意事项:
1)在程序当中 调用一个方法时,同时有隐式值、默认值、和传入值 编译器的采用的优先级为 传值>隐式值>默认值
2)隐式值在匹配时,不能有二义性
3)如果方法调用时 没有传值 同时也没有 隐式值和默认值 那么 程序会报错
示例:

 def test: Unit ={
     implicit val name:String ="Scala";
     //声明两个 String 类型的隐式值 后 程序 在匹配隐式值时  不知道选用哪个 因此会报错
     //即 隐式值不能有二义性
     //implicit val msg:String ="Hello";
     def hello(implicit param:String): Unit ={
       println("hi~"+param)
     }
     def hello2(implicit param:String="默认参数值"): Unit ={
       println("hi~"+param)
     }
     hello //hi~Scala  法参数只有隐式值  因此 输出 隐式值
     hello2//hi~Scala  法参数隐式值和默认值同时存在 使用隐式值
     hello("传入值")//hi~传入值  方法参数有传入值时 使用传入值
     //实时上 使用隐式值 发生在编译阶段 而使用 默认值 发生在 执行阶段,所以 隐式值得优先级比默认值高
 编译后的test方法如下:
    public void test()
  {
    String name = "Scala";

    hello$1(name);
    hello2$1(name);
    hello$1("传入值"); }
   }

隐式类

scala2.10之后提供了隐式类,可以使用implicit声明类,隐式类非常强大,同样可以扩展类的功能
比之前使用隐式转换丰富类功能更加方便,在计划中隐式类会发挥很大的作用
隐式类有以下特点
1)它构造器的参数有且只有一个
2)隐式类必须定义在类、伴生对象或包对象中,不能直接定义在包下(因为这样不明确作用范围)
3)隐式类不能是case class
4)作用域内不能有与之相同名称的标识符
示例:

class Mysql{
    def sayHi(): Unit ={
      println("hi~~~")
    }
  }

   def test: Unit ={
     /*
     声明 DB为隐式类 当在该类的作用域范围内创建 Mysql对象时 该隐式类就会自动生效
     (在调用DB1类的方法时自动根据实例构造DB1实例)
     即 同上述隐式函数转换函数示例 ,
      */
    implicit class DB(val m:Mysql){
       def showInfo(): Unit ={
         println(m.toString +"ddd")
       }

     }
     var mysql=new Mysql
     mysql.sayHi()
     mysql.showInfo()//可以调用 DB 类中的方法
   }

反编译 DB类如下 编译器生成的DB类 拥有一个Mysql类型的属性

 public class class09$DB$1
{
  private final class09.Mysql m;

  public class09.Mysql m()
  {
    return this.m; }

  public void showInfo() { Predef..MODULE$.println(3 + m().toString() + "ddd");
  }
}

test 方法反编译如下,在调用DB的方法时 根据mysql实例创建一个 DB实例 然后执行方法

public final class class09$
{
  public static  MODULE$;

  static
  {
    new ();
  }

  public void test()
  {
    class09.Mysql mysql = new class09.Mysql();
    mysql.sayHi();
    DB$2(mysql).showInfo(); }

  public void main(String[] args) {
    test();
  }

  private static final class09.DB.1 DB$2(class09.Mysql m)
  {
    return new class09.DB.1(m);
  }

  private class09$()
  {
    MODULE$ = this;
  }
}

隐式转换的时机

1)当方法中的参数类型与目标类型不一致时,或者为变量赋值本身类型和目标类型不一直是 val a:Int=3.4
2) 当对象调用本类中不存在的方法或成员时,编译器会自动将对象进行隐式转换

隐式解析机制

编译器是如何查找到缺失信息并完成对应的隐式转换的?
1)首先编译器会在当前代码作用域下查找隐式实体(隐式方法、隐式类、隐式对象)
大部分都是这种情况
2)如果第一条规则查找失败,编译器会继续在隐式参数类型的作用域李查找。
类型的作用域指与该类型相关联的全部伴生模块。一个隐式实体的类型T查找范围如下
(这种情况范围广且复杂,实际开发中尽量避免使用)
a)如果T被定义为 T with A with B with C 那么 ABC 都是T 的部分,在T的隐式解析过程中他们的伴生对象都会被搜索
b)如果T是参数化类型,那么类型参数和与类型参数相关联的部分都算作T的部分,如
List[String]的隐式搜做会搜索List 和 String 的的伴生对象
c)如果T是一个单例类型, p.T,即T属于某个对象p,那么这个p对象也会被搜索
d)如果T是个类型注入 S#T,那么S和T 都会被搜索

隐式转换的前提

隐式转换时需要遵循两个基本前提
1)不能有二义性
2)隐式操作不能嵌套使用

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

catch that elf

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值