📅  最后修改于: 2020-11-02 04:47:52             🧑  作者: Mango
特征封装了方法和字段定义,然后可以通过将它们混合到类中来重用它们。与类继承(每个类只能从一个超类继承)不同,一个类可以混合任意数量的特征。
特性用于通过指定所支持方法的签名来定义对象类型。 Scala还允许部分实现特征,但是特征可能没有构造函数参数。
特征定义看起来像类定义,只是它使用关键字trait 。以下是trait的基本示例语法。
trait Equal {
def isEqual(x: Any): Boolean
def isNotEqual(x: Any): Boolean = !isEqual(x)
}
此特征包含两个方法isEqual和isNotEqual 。在这里,我们没有给出isEqual的任何实现,而另一种方法已经实现了。扩展特性的子类可以为未实现的方法提供实现。因此,特征与Java中的抽象类非常相似。
让我们假设一个特征Equal的示例包含两个方法isEqual()和isNotEqual() 。特征Equal包含一个已实现的方法isEqual(),因此当用户定义的类Point扩展特征Equal时,应提供对Point类中isEqual()方法的实现。
在这里,需要知道两种重要的Scala方法,在以下示例中将使用它们。
obj.isInstanceOf [Point]要检查obj和Point的类型是否相同。
obj.asInstanceOf [Point]表示通过采用对象obj类型进行精确转换,并返回与Point类型相同的obj。
尝试使用以下示例程序来实现特征。
trait Equal {
def isEqual(x: Any): Boolean
def isNotEqual(x: Any): Boolean = !isEqual(x)
}
class Point(xc: Int, yc: Int) extends Equal {
var x: Int = xc
var y: Int = yc
def isEqual(obj: Any) = obj.isInstanceOf[Point] && obj.asInstanceOf[Point].x == y
}
object Demo {
def main(args: Array[String]) {
val p1 = new Point(2, 3)
val p2 = new Point(2, 4)
val p3 = new Point(3, 3)
println(p1.isNotEqual(p2))
println(p1.isNotEqual(p3))
println(p1.isNotEqual(2))
}
}
将以上程序保存在Demo.scala中。以下命令用于编译和执行该程序。
\>scalac Demo.scala
\>scala Demo
true
false
true
值类是Scala中避免分配运行时对象的新机制。它包含一个带有一个val参数的主构造函数。它仅包含不允许使用var,val,嵌套类,特征或对象的方法(def)。值类不能由其他类扩展。这可以通过使用AnyVal扩展值类来实现。自定义数据类型的类型安全性,而没有运行时开销。
让我们以值类重量,身高,电子邮件,年龄等为例。对于所有这些示例,不需要在应用程序中分配内存。
不允许扩展特征的值类。为了允许值类扩展特征,引入了对Any扩展的通用特征。
trait Printable extends Any {
def print(): Unit = println(this)
}
class Wrapper(val underlying: Int) extends AnyVal with Printable
object Demo {
def main(args: Array[String]) {
val w = new Wrapper(3)
w.print() // actually requires instantiating a Wrapper instance
}
}
将以上程序保存在Demo.scala中。以下命令用于编译和执行该程序。
\>scalac Demo.scala
\>scala Demo
它将为您提供Wrapper类的哈希码。
Wrapper@13
没有严格的规则,但是这里要考虑的准则很少-
如果该行为不会被重用,则使其成为一个具体的类。毕竟这不是可重用的行为。
如果可以在多个不相关的类中重用它,请使其成为特征。只有特征可以混入类层次结构的不同部分。
如果要在Java代码中从中继承,请使用抽象类。
如果计划以编译形式分发它,并且希望外部团体编写从其继承的类,则可能倾向于使用抽象类。
如果效率非常重要,则倾向于使用课程。