Scala 中的类是用于创建对象的蓝图。它们可以包含方法、值、变量、类型、对象、特征和类,这些统称为成员。类型、对象和特征将在本教程后面进行介绍。
定义类
最简单的类定义仅包含关键字 class
和一个标识符。类名应大写。
class User
val user1 = new User
关键字 new
用于创建类的实例。
class User
val user1 = User()
我们像调用函数一样调用类,例如 User()
,以创建类的实例。也可以明确使用 new
关键字,例如 new User()
,尽管通常省略该关键字。
User
有一个默认构造函数,该函数不接受任何参数,因为没有定义构造函数。但是,你通常需要一个构造函数和类主体。下面是一个点的示例类定义
class Point(var x: Int, var y: Int) {
def move(dx: Int, dy: Int): Unit = {
x = x + dx
y = y + dy
}
override def toString: String =
s"($x, $y)"
}
val point1 = new Point(2, 3)
println(point1.x) // prints 2
println(point1) // prints (2, 3)
class Point(var x: Int, var y: Int):
def move(dx: Int, dy: Int): Unit =
x = x + dx
y = y + dy
override def toString: String =
s"($x, $y)"
end Point
val point1 = Point(2, 3)
println(point1.x) // prints 2
println(point1) // prints (2, 3)
此 Point
类有四个成员:变量 x
和 y
,以及方法 move
和 toString
。与许多其他语言不同,主构造函数在类签名 (var x: Int, var y: Int)
中。 move
方法接受两个整型参数,并返回单位值 ()
,该值不携带任何信息。这大致对应于类似 Java 的语言中的 void
。另一方面, toString
不接受任何参数,但返回 String
值。由于 toString
覆盖了 AnyRef
中的 toString
,因此它被标记为 override
关键字。
构造函数
构造函数可以通过提供默认值来具有可选参数,如下所示
class Point(var x: Int = 0, var y: Int = 0)
val origin = new Point // x and y are both set to 0
val point1 = new Point(1) // x is set to 1 and y is set to 0
println(point1) // prints (1, 0)
class Point(var x: Int = 0, var y: Int = 0)
val origin = Point() // x and y are both set to 0
val point1 = Point(1) // x is set to 1 and y is set to 0
println(point1) // prints (1, 0)
在此版本的 Point
类中, x
和 y
的默认值 0
,因此不需要参数。但是,由于构造函数从左到右读取参数,因此如果你只想传入 y
值,则需要命名参数。
class Point(var x: Int = 0, var y: Int = 0)
val point2 = new Point(y = 2)
println(point2) // prints (0, 2)
class Point(var x: Int = 0, var y: Int = 0)
val point2 = Point(y = 2)
println(point2) // prints (0, 2)
这也是提高清晰度的好做法。
私有成员和 Getter/Setter 语法
成员默认情况下为公共。使用 private
访问修饰符将它们隐藏在类外部。
class Point {
private var _x = 0
private var _y = 0
private val bound = 100
def x: Int = _x
def x_=(newValue: Int): Unit = {
if (newValue < bound)
_x = newValue
else
printWarning()
}
def y: Int = _y
def y_=(newValue: Int): Unit = {
if (newValue < bound)
_y = newValue
else
printWarning()
}
private def printWarning(): Unit =
println("WARNING: Out of bounds")
}
val point1 = new Point
point1.x = 99
point1.y = 101 // prints the warning
class Point:
private var _x = 0
private var _y = 0
private val bound = 100
def x: Int = _x
def x_=(newValue: Int): Unit =
if newValue < bound then
_x = newValue
else
printWarning()
def y: Int = _y
def y_=(newValue: Int): Unit =
if newValue < bound then
_y = newValue
else
printWarning()
private def printWarning(): Unit =
println("WARNING: Out of bounds")
end Point
val point1 = Point()
point1.x = 99
point1.y = 101 // prints the warning
在此版本的 Point
类中,数据存储在私有变量 _x
和 _y
中。有方法 def x
和 def y
用于访问私有数据。 def x_=
和 def y_=
用于验证和设置 _x
和 _y
的值。注意设置器的特殊语法:方法在 getter 的标识符后附加 _=
,并且参数在之后。
带有 val
和 var
的主构造函数参数是公共的。但是,由于 val
是不可变的,因此无法编写以下内容。
class Point(val x: Int, val y: Int)
val point = new Point(1, 2)
point.x = 3 // <-- does not compile
class Point(val x: Int, val y: Int)
val point = Point(1, 2)
point.x = 3 // <-- does not compile
没有 val
或 var
的参数是私有值,仅在类内可见。
class Point(x: Int, y: Int)
val point = new Point(1, 2)
point.x // <-- does not compile
class Point(x: Int, y: Int)
val point = Point(1, 2)
point.x // <-- does not compile