大数据——Scala特质和型变及示例演示

特质(Trait)

Scala中没有接口(interface)的概念
特质用于在类之间共享程序接口和字段,类似于Java接口
特质是字段和方法的集合,可以提供字段和方法实现
类和单例对象都可以扩展特质(extends)
特质不能被实例化,因此没有构造参数,类似于Java接口
特质使用“trait”关键字定义
实现特质中的方法使用“override”

使用特质

import scala.collection.mutable.ArrayBuffer

trait Pet {
  val name: String
  def cry():Unit
}
class Dog(val name: String) extends Pet{
  override def cry()=println("wow ...")
}
val dog = new Dog("Harry")
val animals = ArrayBuffer.empty[Pet]
animals.append(dog)
animals.foreach(pet => {println(pet.name);pet.cry()})  // Prints Harry wow ...

混入特质(mixin)

当某个特质被用于组合类时,被称为混入
一个类只能有一个父类但是可以有多个混入(分别使用关键字extends和with)

abstract class A {
  val message: String
}
class B extends A {
  val message = "I'm an instance of class B"
}
trait C extends A {
  def loudMessage = message.toUpperCase()
}
//构造顺序由左往右,如果前面已经构造了某个父类,后面子类的该父类不会重复构造
class D extends B with C

val d = new D
println(d.message)  // I'm an instance of class B
println(d.loudMessage)  // I'M AN INSTANCE OF CLASS B

动态混入特质

class Drawing { 
//this:Type=> 自身类型,表示该类实例化时必须混入相应特质或子特质,self是this的别名。
  self: Shape =>
  def start(): Unit = draw()
}
trait Shape {
  def draw(): Unit
}
trait Square extends Shape {
  def draw(): Unit = println("draw a square")
}
trait Triangle extends Shape {
  def draw(): Unit = println("draw a triangle")
}
//动态混入
(new Drawing() with Square).start()
(new Drawing() with Triangle).start()

特质与抽象类的选择

优先使用特质

  • 抽象类只能继承一次
  • 特质可以混入多个

需要使用带参构造方法时,使用抽象类
与Java互操作性

  • 抽象类与Java完全可互操作
  • 特质只有在不包含任何实现代码时才可互操作

示例

package packagetwo

abstract class Car {
  def brand:String
  def engine:String
  def didi():String={
    "汽车鸣笛滴滴滴"
  }
}

class BMW extends Car{
  override def brand: String = {
    "德国宝马"
  }

  override def engine: String = {
    "16缸涡轮增压"
  }
}

class Dazhong extends Car{
  override def brand: String ={
    "上海大众"
  }

  override def engine: String = {
    "18缸火箭喷气"
  }
}

trait Type1{
  def fly:Unit={
    println("可以飞")
  }
}

trait Type2{
  def downsea():Unit={
    println("可以下海")
  }
}

object DemoCar{
  def main(args: Array[String]): Unit = {
    val bmw=new BMW
    println(bmw.brand)
    println(bmw.engine)
    println(bmw.didi())

    val dazhong:Dazhong with Type1 with Type2=new Dazhong with Type1 with Type2
    dazhong.fly
    dazhong.downsea()
    println(dazhong.brand)
    println(dazhong.engine)
  }
}

结果展示:
在这里插入图片描述

型变

协变

class Foo[+T]  // 协变类

对于两种类型A和B,如果A是B的子类型,那么Foo[A]就是Foo[B]的子类型

逆变

class Bar[-T]  // 逆变类

对于两种类型A和B,如果A是B的子类型,那么Bar[B]就是Bra[A]的子类型

不变

class Baz[T]  // 不变类

默认情况下,Scala中的泛型类是不变的

示例

object test {
  //协变点(covariant position)、逆变点(contravariant position)和不变(invariant)
  class Animal{

    def eat():Unit={
      println("动物要吃食物")
    }
  }
  class Cat extends Animal{
    override def eat(): Unit = println("猫吃鱼")
  }
  class Tiger extends Cat{
    override def eat(): Unit = println("老虎吃肉")
  }
  class Invariant[T]{//不变

  }
  class Covariant[+T]{//协变
    
  }
  class Inversion[-T]{//逆变
    
  }

  def main(args: Array[String]): Unit = {
    var cat=new Cat
    var tiger=new Tiger
    
    val cat2:Cat=tiger
    val bubian:Invariant[Cat]=new Invariant[Cat]
    val bubianTiger:Invariant[Tiger]=new Invariant[Tiger]
    
    /*报错(在泛型里不变的情况下Invariant[T],Invariant[Cat]与Invariant[Tiger]没有任何变系):
    val bubian2:Invariant[Cat]=bubianTiger*/
    
    val xieCat:Covariant[Cat]=new Covariant[Cat]
    val xietiger:Covariant[Tiger]=new Covariant[Tiger]
    val xieCat2:Covariant[Cat]=xietiger
    
    val nicat:Inversion[Cat]=new Inversion[Cat]
    val nitiger:Inversion[Tiger]=new Inversion[Tiger]
    val nitiger2:Inversion[Cat]=nicat
  }
}
已标记关键词 清除标记
©️2020 CSDN 皮肤主题: 游动-白 设计师:上身试试 返回首页