特质(trait)是scala里代码复用的基础单元。 特质封装了方法和字段的定义, 并可以通过混入到类中复用它们。 与类的继承时每个类都只能继承唯一的超类不同, 类可以混入任意多个特质。
当做接口使用的特质
Scala的特质完全可以像Java的接口那样工作。例如:
trait Logger{
def log(msg:String) // 抽象方法
}
class ConsoleLogger extends Logger{
// 使用 extends 而不是Java 中的 implements
// 不需要写 override
def log(msg: String): Unit = {
println(msg)
}
}
trait 不需要你将方法声明为abstract,未被实现的方法默认就是抽象的; 在重写特质的抽象方法时也不需要给出override关键字。
使用反编译看下上述样例Java的定义:
// borey-zhu@AWS-TEST-DT:~/scala$ scalac log.scala
// borey-zhu@AWS-TEST-DT:~/scala$ ls
// ConsoleLogger.class Logger.class log.scala
// borey-zhu@AWS-TEST-DT:~/scala$ javap -p Logger.class
// Compiled from "log.scala"
public interface Logger {
// 生成java接口
public abstract void log(java.lang.String);
}
// borey-zhu@AWS-TEST-DT:~/scala$ javap -p ConsoleLogger.class
// Compiled from "log.scala"
public class ConsoleLogger implements Logger {
// 实现接口
public void log(java.lang.String);
public ConsoleLogger();
}
带有具体实现的特质
在Scala中,特质中的方法并不需要一定是抽象的。 例如:
trait Logger{
def log(msg: String): Unit = {
println(msg)
}
}
class Person(val Name:String){
}
class Student(name:String) extends Person(name) with Logger{
def learn(): Unit ={
log(Name + "is learning ... ")
}
}
注意: Student 从 Logger特质得到了一个具体的 log方法实现。 用Java接口的话, 这是不可能做到的。
对上述样例进行反编译,查看java是怎么进行定义的:
// borey-zhu@AWS-TEST-DT:~/scala$ javap -p Logger.class
// Compiled from "log.scala"
public interface Logger {
// log 方法带有具体的实现,会生成对应的静态方法
public static void log$(Logger, java.lang.String);
public void log(java.lang.String);
public static void $init$(Logger);
}
// borey-zhu@AWS-TEST-DT:~/scala$ javap -p Student.class
// Compiled from "log.scala"
public class Student extends Person implements Logger {
public void log(java.lang.String);
public void learn();
public Student(java.lang.String);
}
带有特质的对象
在构造单个对象时, 你可以为它添加特质。 例如:
trait Logger{
// 带一个什么都没有做的实现
def log(m