原创转载请注明出处: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编程思想
Scala特性详解
53

被折叠的 条评论
为什么被折叠?



