从面向对象来看,接口并不属于面线对象的范畴,Scala是纯面向对象的语言,所以Scala中没有接口。为了弥补没有接口的缺点,开发者提出了trait 特质的概念。
1、trait的声明
trait 特质名 {
trait 体
}
(trait 命名 一般首字母大写)
2、一个类具有某种特质时,可以使用extends 关键字 ,如存在多个特质,那么必须使用with 关键字连接,例如:
1)没有父类
class 类名 extends 特质1 with 特质2 with 特质 3 …
2)有父类
class 类名 extends 父类 with 特质1 with 特质2 with 特质 3 … (有父类 必须先继承父类才行)
入门案例:
//定义一个 Trait01 特质
trait Trait01{
//写了个抽象方法
def getConnect()
}
//定义几个类使其有继承关系
class A{}
class B extends A{}
// 如果有继承关系 要先把继承的父类写在前面
class C extends B with Trait01 {
//重写了抽象方法
override def getConnect(): Unit = {
println("连接MySQL")
}
}
val c = new C
c.getConnect()
class D{}
class E extends D{}
class F extends D with Trait01 {
override def getConnect(): Unit = {
println("连接oracle")
}
}
val f = new F
f.getConnect()
3、trait 特质再说明:
特质可以拥有抽象方法和具体方法
4、带有特质的对象,动态混入:
除了可以在声明类时继承特质以外,还能在构建对象时混入特质,扩展目标类的功能
案例说明:
//定义一个特质
trait Operate3{
def insert(id:Int): Unit ={
println("插入数据:"+id)
}
}
//普通类
class OracleDB{
}
//抽象类
abstract class Mysql{
}
//抽象类含有抽象方法
abstract class mysql_1{
def insert()
}
//普通类动态混入特质
val oracleDB = new OracleDB with Operate3
oracleDB.insert(12)
//抽象类无方法 混入动态特质
val mysql = new Mysql with Operate3
mysql.insert(18)
//抽象类 含有抽象方法的 进行动态混入
val my = new mysql_1 with Operate3 {
//其抽象方法必须被重写
override def insert(): Unit = {
println("插入数据")
}
}
my.insert(33) //特质方法的调用
my.insert() //重写了抽象类中方法的调用
5、扩展类的特质:
特质可以继承类,用来拓展该特质的功能
// 例如:
trait LoggedException extends Exception{
def log(): Unit ={
println(getMessage()) //方法来自于 Exception
}
}
class UnhappyException extends LoggedException{
// 由于 LoggedException 继承了 Exception
//UnhappyException 再继承 LoggedException
// 所以 可以改写 getMessage 方法
override def getMessage =
"错误消息"
}
val unhappyException = new UnhappyException
println(unhappyException.getMessage) //输出:错误消息
注意事项:
1、所有混入该特质的类,会自动成为那个特质所继承的超类的子类
2、如果混入该特质的类,已经继承了另一个类(A类),则要求A类是特质超类的子类,否则会出现多继承现象,报错
错误示例:
// 定义一个普通类
class CCC{}
class UnhappyException3 extends CCC with LoggedException{
override def getMessage: String = "错误消息!"
}
//以上代码编译时会报错 因为CCC 不是 Exception 的 子类,从而产生了 多继承现象
6、自身类型:
解决特质的循环依赖问题,同时确保特质可以在不扩展某个类的情况下,依然可以做到限制混入该特质的类的类型。
// An highlighted block
trait Logger{
//this:Exception => 明确告诉编译器,我就是Exception,
// 如果没有这句话,下面的getMassage 不能调用
this:Exception =>
def log():Unit={
//既然我就是Exception,那么就可以调用其中的方法
println(getMessage)
}
}