原创转载请注明出处:http://agilestyle.iteye.com/blog/2334648
Scala中的trait,相当于Java中interface,支持多种继承,但是语法还是有些差异的。
使用trait关键字定义特征,将多个特征组合到一个类中,需要以extends关键字开头,然后使用with关键字添加额外的特征
package org.fool.scala.traits trait Color trait Texture trait Hardness class Fabric class Cloth extends Fabric with Color with Texture with Hardness class Paint extends Color with Texture with Hardness object Materials extends App { new Fabric new Cloth new Paint }
跟抽象类一样,特征中的域和方法可以有定义,也可以是抽象的
package org.fool.scala.traits trait AllAbstract { def f(n: Int): Int val d: Double } trait PartialAbstract { def f(n: Int): Int val d: Double def g(s: String) = s"($s)" val j = 42 } trait Concrete { def f(n: Int) = n * 11 val d = 1.8 }
单独的特征是不能实例化的,因为它没有全功能的构造器。
/* None of these are legal -- traits cannot be instantiated: new AllAbstract new PartialAbstract new Concrete */
在组合特征来生成新类时,所有域和方法都必须有定义,否则Scala会强制要求该类必须包含abstract关键字
// Scala requires 'abstract' keyword: abstract class Klass1 extends AllAbstract with PartialAbstract /* Can't do this -- d and f are undefined: new Klass1 */
这些定义可以由新类提供,e.g. Klass2,或者通过其他特征实现,e.g. Klass3、Klass4、Klass5中的Concrete(抽象类中的方法也支持这种操作)
class Klass2 extends AllAbstract { def f(n: Int) = n * 12 val d = 3.14 } class Klass3 extends AllAbstract with Concrete class Klass4 extends PartialAbstract with Concrete class Klass5 extends AllAbstract with PartialAbstract with Concrete new Klass2 new Klass3 new Klass4 new Klass5
特征可以被抽象类或具体类继承
trait FromAbstract extends Klass1 trait FromConcrete extends Klass2
特征不能有构造器参数,但可以有构造器体
trait Construction { println("Constructor body") } class Constructable extends Construction new Constructable
Console Output
show an interesting trick: creating an instance of a class that you assemble at the site of creation. The resulting object has no type name. This technique creates a single instance of an object without creating a new named class just for that one usage.
val x = new AllAbstract with PartialAbstract with Concrete
特征可以继承其他特征
package org.fool.scala.traits trait Base { def f = "f" } trait Derived1 extends Base { def g = "17" } trait Derived2 extends Derived1 { def h = "1.23" } class Derived3 extends Derived2 object TraitInheritance extends App { val d = new Derived3 println(d.f) println(d.g) println(d.h) }
Console Output
组合特征时,有可能会将具有相同签名(方法与类型的组合)的两个方法混合在一起。如果方法或域的签名产生冲突,那么需要人工解决这种冲突,e.g. 在object C中看到的那样(这里object起到快捷方式的作用,通过它可以创建类,然后创建该类的一个实例)
package org.fool.scala.traits trait A { def f = 1.1 def g = "A.g" val n = 7 } trait B { def f = 2.2 def g = "B.g" val n = 17 } object C extends A with B { override def f = 3.3 override def g = super[A].g + super[B].g override val n = 27 } object TraitCollision extends App { println(C.f) println(C.g) println(C.n) }
Console Output
特征域和方法即使还未被定义,也可以在计算中使用它们
package org.fool.scala.traits trait Framework { val part1: Int def part2: Double // even without definitions: def templateMethod = part1 + part2 } class Implementation extends Framework { override val part1 = 12 override def part2 = 1.23 } object FrameworkTest extends App { def operation(impl: Framework) = impl.templateMethod println(operation(new Implementation)) }
Console Output
参考资料:
Scala编程思想