教学互动网站开发背景/企业网站建设方案范文
Scala特质和型变及示例演示
- 特质(Trait)
- 使用特质
- 混入特质(mixin)
- 动态混入特质
- 特质与抽象类的选择
- 示例
- 型变
- 协变
- 逆变
- 不变
- 示例
特质(Trait)
Scala中没有接口(interface)的概念
特质用于在类之间共享程序接口和字段,类似于Java接口
特质是字段和方法的集合,可以提供字段和方法实现
类和单例对象都可以扩展特质(extends)
特质不能被实例化,因此没有构造参数,类似于Java接口
特质使用“trait”关键字定义
实现特质中的方法使用“override”
使用特质
import scala.collection.mutable.ArrayBuffertrait Pet {val name: Stringdef 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 Cval 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 packagetwoabstract class Car {def brand:Stringdef engine:Stringdef 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 BMWprintln(bmw.brand)println(bmw.engine)println(bmw.didi())val dazhong:Dazhong with Type1 with Type2=new Dazhong with Type1 with Type2dazhong.flydazhong.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 Catvar tiger=new Tigerval cat2:Cat=tigerval 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]=xietigerval nicat:Inversion[Cat]=new Inversion[Cat]val nitiger:Inversion[Tiger]=new Inversion[Tiger]val nitiger2:Inversion[Cat]=nicat}
}