每日一篇Scala每日一篇大数据程序员技术栈

Scala(六)-①-面相对象高级-特质(下)-嵌套类-隐式转换

2018-11-19  本文已影响6人  sixleaves

① 特质(下)

在上一篇博文中,我已经介绍了Scala中静态属性和方法之伴生对象实现,以及特质入门的一部分内容.该篇博文我将会介绍特质(下)、嵌套类、隐式(上).对于特质(下).我主要介绍以下主题, 叠加特质自身类型嵌套类

Why

叠加特质

为什么我们要学习叠加特质,这是因为Scala中并无多重继承,因为多重继承会带来很多问题, 为了能够实现多重继承又能规避其问题, Scala使得特质能够叠加,通俗说是让一个类能够具备多个特质.

自身类型(强制规定能够混入特质的类)

自身类型主要是为了解决特质的循环引入,即因为混入特质而形成的依赖回环.该技术
通过再特质中明确规定哪些类能够混入该特质来解决这个问题.

How

叠加特质

规则和语法
// 创建一个SomeObject对象,混入Trait1和Trait2特质
val obj = new SomeObject with Trait1 with Trait2
叠加特质Demo

代码

object TraitDemo05MultiplyMixin {
  def main(args: Array[String]): Unit = {

    val mysql = new MySQL with DB with File
    mysql.insert(100)
  }
}

class MySQL {}


trait Operator {

  def insert(id :Int)
}

trait Data extends Operator {
  override def insert(id: Int): Unit = {
    println("插入数据")
  }
}

trait DB extends Data {
  override def insert(id: Int): Unit = {
    println("向数据库插入数据")
    super.insert(id)
  }
}

trait File extends Data {
  override def insert(id: Int): Unit = {
    println("向文件中插入数据")
    super.insert(id)
  }
}

输出

向文件中插入数据
向数据库插入数据
插入数据
object TraitDemo05MultiplyMixin02 {
  def main(args: Array[String]): Unit = {

    val mysql = new MySQL05 with DB05 with File05
  }
}

class MySQL05 {}


trait Operator05 {
  println("Operator")
}

trait Data05 extends Operator05 {
  println("Data")
}

trait DB05 extends Data05 {
  println("DB")
}

trait File05 extends Data05 {
  println("File")
}

输出

Operator
Data
DB
File

自身类型

代码

object TraitDemo09SelfTypeForCycleRefenrece {

  def main(args: Array[String]): Unit = {
//      val oracle = new Oracle09 with Logger // 错误
    var mysql = new MySQL09 with Logger
  }

}

trait Logger {
  // 声明混入该特质的类必须是Exception或者其子类
  this:Exception=>
  def log(): Unit = {
    getMessage
  }
}

class Oracle09 {}

class MySQL09 extends Exception {

}

What

叠加特质

Details

叠加特质

object TraitDemo06RichInterface {

  def main(args: Array[String]): Unit = {
    val mySQL = new MySQL06 with DBDriver06 {
      // 实现抽象字段
      override var numberOfThread: Int = _

      // 实现抽象方法
      override def delete: Unit = {

      }
    }

  }
}

class MySQL06 { }

trait DBDriver06 {

  var numberOfThread : Int
  private var operatorType = "insert"

  def insert(): Unit = {

  }

  def delete
}

特质构造分两种,一种声明时混入,一种动态混入(new的时候混入).两种唯一的区别是,动态混入先构造本类,而声明时混入最后才构造本类,其它都一样.

代码

object TraitDemo07DecalreMixin {
  def main(args: Array[String]): Unit = {
    println("声明时混入")
    
    val ff = new FF

    println("动态混入")
    // 动态混入
    val ee = new EE with CC with DD


  }
}

trait AA {
  println("A...")
}
trait BB extends  AA {
  println("B....")
}
trait CC extends  BB {
  println("C....")
}
trait DD extends  BB {
  println("D....")
}

class EE {
  println("E...")
}

// 声明时混入ee、cc、dd
class FF extends EE with CC with DD {
  println("F....")
}

// 声明时混入ee
class KK extends EE {
  println("K....")
}

输出

声明时混入
E...
A...
B....
C....
D....
F....
动态混入
E...
A...
B....
C....
D....
object TraitDemo08ExtendTrait {
  def main(args: Array[String]): Unit = {
    val log = new Log4Scala

  }
}


trait Log extends Exception {

  def log: Unit = {
    getMessage
  }
}
// 如果去掉LogModule继承Exception,则运行时会报错,提示多重继承
class LogModule extends Exception{

}

class Log4Scala extends LogModule with Log {

}

② 嵌套类

Java中内部类

嵌套类对应Java的内部类,所以我们先来看看Java中的内部类.在Java中,一个类总共有五大>成员.分别是

  • 属性
  • 方法
  • 内部类
  • 构造器
  • 代码块

Java中内部类
在Java中一个类里面可以再嵌套一个类,嵌套在里面的类被称为内部类,在外面的类称为

外部类.

Why

为什么Java中有内部类,为了解决什么问题?Java中的内部类主要为了解决不同类之前无法访>问其私有成员的问题.内部类就可以访问外部的私有成员.

How
class OuterClass {
  class InnserClass { // 成员内部类,位于成员位置且不为静态
  
  }
  
  static class StaticInnerClass {  // 静态内部类, 位于成员位置,且为静态
  
  }
  
  public void test() {
       class InnerClass02 { // 局部内部类· 位于方法,有类名
       
       }
       
       new Thread() {  // 匿名内部类
           @Override
           public void run() {
               super.run();
           }
       }.start();
  }
}


Why

为什么Scala中也要有嵌套类?

Scala中也有内部类的概念, Scala中又称为嵌套类.也就是说嵌套是为支持Java中的内部类概念.

How

语法和规则
/**
  * @author sweetcs
  */
object InnerClassDemo01ForCreate {
  def main(args: Array[String]): Unit = {

    val outer01 = new ScalaOuterClass01
    val outer02 = new ScalaOuterClass01

    val inner01 = new outer01.ScalaInnerClass01
    val inner02 = new outer02.ScalaInnerClass01
    val inner03 = new ScalaOuterClass01.ScalaStaticInnerClass01

    inner01.showInfo(inner01)
    inner01.showInfoWithAlia()
//    inner01.showInfo(inner02) // 类型不匹配

  }
}

/**
  * Scala的成员内部类创建方式 `new 外部类实例.内部类`.Scala的成员内部类类型和外部类实例关联(Scala内部类是从属于外部类对象的).这两点都和Java的成员内部类有区别
  */

object ScalaOuterClass01 {

  // 静态内部类
  class ScalaStaticInnerClass01 {

    def showInfo(): Unit = {

      println("ScalaStaticInnerClass01")
    }
  }

}

class ScalaOuterClass01 {
  // 给外部类起别名为outer
  outer=>
  var name = "scott"
  private var age = 11
  // 成员内部类
  class ScalaInnerClass01 {

    def showInfo(inner: ScalaInnerClass01): Unit = {
      println(s"name=${ScalaOuterClass01.this.name} age = ${ScalaOuterClass01.this.age}")
    }

    def showInfoWithAlia(): Unit = {
      println(s"name=${outer.name} age = ${outer.age}")
    }
  }
}    
    //下面的 ScalaOuterClass#ScalaInnerClass 类型投影的作用就是屏蔽 外部对象对内部类对象的影响
    def test(ic: ScalaOuterClass#ScalaInnerClass): Unit = {
      System.out.println("使用了类型投影" + ic)
    }

③ 隐式转换

① Why

为什么Scala中需要隐式转换和隐式参数

② How

语法和规则
implicit def functionName(形参名:转换类型) : 目标类型 = { 
    // 转换逻辑
}
implicit name :类型 = xxx
implicit def functionName(implicit 形参名:转换类型) : 目标类型 = { 
    // 转换逻辑
}
隐式转换emo
/**
  * @author sweetcs
  */
object ImplicitDemo01 {

  def main(args: Array[String]): Unit = {


    implicit def f1(num:Double) :Int = { // 底层生成了f1$1
      num.toInt
    }

    val num : Int = 3.5 // 底层编译f1$1(3.5)
    println(s"num=${num}")
  }
}
/**
  * @author sweetcs
  */
object ImplicitDemo02 {
  def main(args: Array[String]): Unit = {

    implicit def addDelete(mysql :MySQL) : DB = {
      new DB
    }

    val mysql = new MySQL
    mysql.insert()
    mysql.delete()
  }
}

class MySQL {

  def insert(): Unit = {
    println("Mysql inserting")
  }
}

class DB {

  def delete(): Unit = {
    println("DB deleting")
  }
}
隐式参数DEMO
/**
  * @author sweetcs
  */
object ImplicitDemo03ForImplicitParamter {
  def main(args: Array[String]): Unit = {

      implicit var city :String = "beijing"

      implicit def queryDetailInfo(implicit city :String): Unit = {
        println(city)
      }
      queryDetailInfo
  }
}

③ What

隐式函数底层实现

如口类-ImplicitDemo01

public final class ImplicitDemo01
{
  public static void main(String[] paramArrayOfString)
  {
    ImplicitDemo01$.MODULE$.main(paramArrayOfString);
  }
}

实际入口类-ImplicitDemo01$

public final class ImplicitDemo01$
{
  public static final  MODULE$;
  
  private final int f1$1(double num)
  {
    return (int)num;
  }
  
  public void main(String[] args)
  {
    int num = f1$1(3.5D);
    Predef..MODULE$.println(new StringContext(Predef..MODULE$.wrapRefArray((Object[])new String[] { "num=", "" })).s(Predef..MODULE$.genericWrapArray(new Object[] { BoxesRunTime.boxToInteger(num) })));
  }
  
  private ImplicitDemo01$()
  {
    MODULE$ = this;
  }
  
  static
  {
    new ();
  }

④ Details

implicit def a(d: Double) = d.toInt
implicit def b(d: Double) = d.toInt
val i: Int = 3.5 // 编译期会不知道要调用哪个,因为具有二义性

④ 隐式类

Why

隐式类

How

Demo

/**
  * @author sweetcs
  */
object ImplicitDemo04ForImplicitClass {

  def main(args: Array[String]): Unit = {
    // 在隐式类的作用域内创建MySQL04类的对象,该隐式类自动转换就会生效
    implicit class DB04(mysql :MySQL04) {
        def insert(): Unit = {
          println("插入数据")
        }
    }

    val mysql = new MySQL04
    mysql.getConnection()
    
    mysql.insert()  // 返回了一个ImplicitDemo04ForImplicitClass$DB04$2实例,并调用其insert方法

  }
}

class MySQL04 {

  def getConnection(): Unit = {
    println("获取数据库连接")
  }

}

What

隐式类底层是如何转换成的?
隐式类-程序入口类-ImplicitDemo04ForImplicitClass

public final class ImplicitDemo04ForImplicitClass
{
  public static void main(String[] paramArrayOfString)
  {
    ImplicitDemo04ForImplicitClass$.MODULE$.main(paramArrayOfString);
  }
}

ImplicitDemo04ForImplicitClass$类


public final class ImplicitDemo04ForImplicitClass$
{
  public static final  MODULE$;
  
  private final ImplicitDemo04ForImplicitClass$DB04$2 DB04$1(MySQL04 mysql)
  {
    return new ImplicitDemo04ForImplicitClass$DB04$2(mysql);
  }
  
  public void main(String[] args)
  {
    MySQL04 mysql = new MySQL04();
    mysql.getConnection();
    DB04$1(mysql).insert();
  }
  
  private ImplicitDemo04ForImplicitClass$()
  {
    MODULE$ = this;
  }
  
  static
  {
    new ();
  }
}

ImplicitDemo04ForImplicitClassDB042

public class ImplicitDemo04ForImplicitClass$DB04$2
{
  public void insert()
  {
    Predef..MODULE$.println("插入数据");
  }
  
  public ImplicitDemo04ForImplicitClass$DB04$2(MySQL04 mysql) {}
}

Details

隐式转换时机总结

上一篇 下一篇

猜你喜欢

热点阅读