Scala 基础-类(第一章)

1. 类

  • Scala 中的类是用于创建对象的蓝图,其中包含了类、对象、方法、常量、变量、类型、特质,这些统称为成员
  • Scala 中没有 static 关键字,class 中定义的是非静态的,而 object 中所有的都是静态的

1. class

Scala 是完全面向函数的语言,所以类也是函数,可以使用小括号作为函数的参数列表,使用 new 来创建类实例

1. 基本语法

1
2
3
4
5
6
7
8
class 类名(形参列表) {      // 主构造器
// 类体
def this(形参列表) { // 辅助构造器
}

def this(形参列表) { // 辅助构造器可以有多个...
}
}

2. 构造器

  • 在类的后面声明的构造方法是主构造方法,在主构造方法中声明的构造方法就是辅助构造方法
  • 如果主构造器无参数,小括号可省略,构建对象时调用的构造方法的小括号也可以省略
  • 辅助构造方法不能直接构建对象,必须直接或者间接调用主构造方法
  • 构造器调用其他另外的构造器,要求被调用构造器必须提前声明
  • 如果想让主构造器变成私有的,可以在()之前加上 private,这样用户不能直接通过主构造器来构造对象了(可以通过伴生对象访问)
1
2
3
4
5
6
7
8
9
10
11
// class Person {} 就是 class Person() {}
class Person private(s: String) {

def this(s: String, ss: String) { // 辅助构造方法
this(s) // 直接调用主构造器,且放在第一行
println("辅助构造方法2")
}
def this() { // 辅助构造方法可以有多个
this("辅助构造方法1", "xxxx") // 间接调用主构造器,因为def this(s: String, ss: String)中调用了主构造器
}
}

3. 构造器参数

Scala 类的主构造器函数的形参包括三种类型:未用任何修饰、var 修饰、val 修饰

  • 未用任何修饰: 其是一个局部变量
  • var: 作为类的成员属性使用,可以修改
  • val: 作为类只读属性使用,不能修改
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
class Person(name: String, var age: Int, val sex: String) {

}

object Test {
def main(args: Array[String]): Unit = {
var person = new Person("bobo", 18, "男")
// (1)未用任何修饰符修饰,这个参数就是一个局部变量
// printf(person.name)
// (2)var 修饰参数,作为类的成员属性使用,可以修改
println(person.age)
person.age = 19
println(person.age)
// (3)val 修饰参数,作为类的只读属性使用,不能修改
// person.sex = "女"
println(person.sex)
}
}

构造器可以通过提供一个默认值来拥有可选参数,由于构造器是从左往右读取参数,所以如果仅仅要传y的值,需要带名传参

1
2
3
4
5
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)
val point2 = new Point(y=2)

4. 变量和getter/setter

成员变量默认是 public,使用 private 访问修饰符可以在类外部隐藏它们

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
class Point {
private var _x = 0
private var _y = 0
private val bound = 100

// 类似于 java 中的 get 方法
def x = _x
// 类似于 java 中的 set 方法,此处很特殊,其是在 get 方法后面加上 _=,后面跟着参数
def x_= (newValue: Int): Unit = {
if (newValue < bound) _x = newValue else printWarning
}

def y = _y
def y_= (newValue: Int): Unit = {
if (newValue < bound) _y = newValue else printWarning
}

private def printWarning = println("WARNING: Out of bounds")
}

val point1 = new Point
point1.x = 99
point1.y = 101 // prints the warning

数据存在私有变量 _x_y 中。def xdef y 方法用于访问私有数据。def x_=def y_= 是为了验证和给 _x_y 赋值。

2. object

其类的单例对象,其中定义的均为静态,如果对象的名称和类名相同,这个对象就是伴生对象。

1. 基本语法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
object ClassAndObj {
// object中定义的属性都是静态的
val name = "wangwu"

// 当给对象传入参数时,默认会调用apply方法
def apply(i: Int) = {
println("Score is " + i)
}
// apply可以重写
def apply(i: Int, s: String) = {
println("name is " + s + ",Score is " + i)
}

def main(args: Array[String]): Unit = {
// 对象不可以传参,当看到代码中出现为对象传参的情况,就说明代码中肯定会有一个apply方法
ClassAndObj(30)
ClassAndObj(30,"zhangsan")
}
}

3. 伴生对象和伴生类

在同一个文件中当一个 object 和 class 同名时,称这个 object 是 class 的伴生对象,class 是 object 的伴生类。伴生类和它的伴生对象必须定义在同一个源文件里。
类和它的伴生对象可以互相访问其私有成员。使用伴生对象来定义那些在伴生类中不依赖于实例化对象而存在的成员变量或者方法。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
class Email(val username: String, val domainName: String)

object Email {
def fromString(emailString: String): Option[Email] = {
emailString.split('@') match {
case Array(a, b) => Some(new Email(a, b))
case _ => None
}
}
}

val scalaCenterEmail = Email.fromString("scala.center@epfl.ch")
scalaCenterEmail match {
case Some(email) => println(
s"""Registered an email
|Username: ${email.username}
|Domain name: ${email.domainName}
""")
case None => println("Error: could not parse email")
}

伴生对象 object Email 包含有一个工厂方法 fromString 用来根据一个 String 创建 Email 实例