Scala/类
在 Scala 中,类是一种带有成员的类型,例如字段和方法。类实例可以使用值进行参数化,类可以使用类型进行参数化,这在Scala/类型参数中介绍。
一个简单的类示例
class SimpleClass
val simple1 = new SimpleClass
val simple2 = new SimpleClass
在第一行,关键字 "class" 用于开始类定义。 "class" 后面是类名 "SimpleClass"。这定义了一个名为 "SimpleClass" 的类。在第二行,一个名为 "simple1" 的值被赋值为表达式 "new SimpleClass" 的结果。 "new" 关键字根据类名创建一个实例并返回对该实例的引用,"new SimpleClass" 创建一个 "SimpleClass" 类型的新的实例。在第三行,一个名为 "simple2" 的值被赋值为表达式 "new SimpleClass" 的结果,创建了另一个 "SimpleClass" 类型的新的实例。因此,名为 "simple1" 和 "simple2" 的值各自保存对 "SimpleClass" 类型不同实例的引用。
类可以包含诸如字段之类的成员
class FieldsClass {
val name = "SomeName"
var num = 0
}
在第一行,声明了一个名为 "FieldsClass" 的类。在 "FieldsClass" 名字后面是 "{",它开始了类定义的主体。第二行声明了一个字段,在本例中是一个名为 "name" 的值,被赋值为字符串 "SomeName"。第三行也声明了一个字段,在本例中是一个名为 "num" 的变量,被赋值为数字 '0'。第四行包含一个关闭的 "}",它结束了类定义的主体。
可以使用 "." 访问类的成员
val fields1 = new FieldsClass
val fields2 = new FieldsClass
fields1.num = 3
fields2.num = 16
println("fields1.num is: " + fields1.num) //Prints "fields1.num is: 3".
println("fields2.num is: " + fields2.num) //Prints "fields2.num is: 16".
第一行和第二行声明了两个名为 "fields1" 和 "fields2" 的值,它们各自包含对 "FieldsClass" 实例的引用。第三行从 "fields1.num" 开始。"." 用于访问实例的成员。"." 之前的表达式指定实例,"." 后的名称指定成员。在本例中,指定的实例是 "fields1" 中引用的实例,指定的成员是字段 "num"。在 "fields1.num" 后面是一个赋值,它使用数字 3,将数字 3 赋值给第一个 "FieldsClass" 实例中的 "num" 字段。第四行与第三行类似,但数字 16 被赋值给第二个 "FieldsClass" 实例中的 "num" 字段。第五行和第六行访问两个实例并打印它们 "num" 字段的值,第一个实例的值为 3,第二个实例的值为 16。
类也可以有函数作为成员。这些函数被称为方法
class Counter {
var count = 0
def incrementAndGet = {count += 1; count}
}
val counter1 = new Counter
println("Count is: " + counter1.count) //Prints "Count is: 0".
println("Count is: " + counter1.incrementAndGet) //Prints "Count is: 1".
println("Count is: " + counter1.count) //Prints "Count is: 1".
在第一行到第四行,定义了一个名为 "Counter" 的类。第三行定义了一个方法,就像定义一个函数一样。在第五行,创建了一个新的 "Counter" 实例并赋值给名为 "counter1" 的值。
在第六行,打印实例的计数,即 0。在第七行,使用 "." 访问 "Counter" 的 "incrementAndGet" 方法,就像访问其他成员一样,并调用它。注意,该方法在将计数加 1 后将计数赋值给 incrementAndGet,因此打印的实例计数为 1。在第八行,再次打印实例计数,给出增加后的值 1。
类实例可以使用构造函数通过值进行参数化。一个简单的例子
class Circle(r:Double) {
def area = math.Pi * math.pow(r, 2)
}
val circle1 = new Circle(10.0)
val circle2 = new Circle(20.0)
println("Circle 1's area: " + math.round(circle1.area)) //Prints "Circle 1's area: 314".
println("Circle 2's area: " + math.round(circle2.area)) //Prints "Circle 2's area: 1257".
第一行开始声明一个名为 "Circle" 的新类。在名字后面是 "(r:Double)",它定义了类的主要构造函数。主要构造函数包含一对圆括号,其中包含以逗号分隔的参数列表及其类型。在本例中,定义了一个名为 "r" 的参数,其类型为 "Double"。第二行定义了一个用于计算圆形面积的方法,该方法使用主要构造函数中定义的参数 "r",第三行结束了类定义。第四行定义了一个名为 "circle1" 的新值,并将其赋值为表达式 "new Circle(10.0)" 的结果。圆括号包含传递给 "Circle" 的主要构造函数的参数,在本例中为 "10.0"。因此,"circle1" 包含对 "Circle" 实例的引用,该实例使用 "r" 等于 "10.0" 进行参数化。第五行也是一样的,除了 "circle2" 实例的 "r" 等于 "20.0"。在第六行和第七行,打印圆形的面积。
在类中声明参数列表时,有三种限定符选项:无、"val" 和 "var"。如果没有限定符,如前所述,只能在类内部访问参数。如果限定符是 "val",则可以在类外部访问参数,但不能对其赋值。如果限定符是 "var",则可以在类外部访问参数,并且可以对其赋值。
在参数列表中使用 "val" 的示例
class Point(val x:Int, val y:Int, val z:Int)
val p1 = new Point(3, 10, -5)
println("p1's coordinates are: " + p1.x + ", " + p1.y + ", " + p1.z) //Prints "p1's coordinates are: 3, 10, -5".
在第一行中,所有参数都被 "val" 限定。在第二行中,构造了一个 "Point" 实例,在第三行中,在 "Point" 的定义之外访问了 "Point" 实例的参数。
在参数列表中使用 "var" 的示例
class Accumulator(var sum:Int)
val accumulator1 = new Accumulator(30)
println("Sum is: " + accumulator1.sum) //Prints "Sum is: 30".
accumulator1.sum += 50
println("Sum is: " + accumulator1.sum) //Prints "Sum is: 80".
辅助构造函数是类的替代构造函数,在类中定义为名为 "this" 的方法。类可以有多个辅助构造函数,但它们应该具有不同的签名,并且必须调用之前定义的构造函数。
class Car(val color:String,val year:Int)
{
def this(){
this("Black",2010) //Auxiliary constructor with defaults
}
def this(color:String) {
this(color,2010)
}
def this(year:Int){
this("Black",year)
}
}
object Car {
def main(args:Array[String])= {
//You can instantiate the Car with different constructor signatures
val blackCar = new Car()
val redCar = new Car("Red")
val defCar = new Car("Green", 2013)
val oldCar = new Car(1990)
}
}
在上面的示例中,我们有三个辅助构造函数。