Scala 编程之类与对象
一. 类用法
package org.example
class Person(var height: Int) {
height = height + 1
println("父类构造方法被调用了:" + height)
}
// 类名称(成员变量......)
// 成员包括:属性(常量、变量)、方法
// 不带 val或var 的参数等同于 private val,在初始化以后就不会变化
class Student(var initHeight: Int,
var name: String,
val age: Int = 18,
address: String) extends Person(initHeight) { // 父类构造方法在这里被调用的, initHeight是临时使用一下
// initHeight 是要传递给父类的
// name age 是 public 的, age 的默认值为 18,age 是常量不能更改
// address 是 private 的常量
// 这里属于主构造方法,在 new Student 的时候被调用
name = "name:" + name
// public的成员方法,用于公开address
def getAddress: String = address
// 定义新的成员变量、成员常量
var school: String = "beijing university"
val grade: String = "junior"
// 主构造函数:其实就是把类成员初始化
// 辅助构造函数:额外的构造函数,每个辅助构造方法都必须首先调用另一个构造方法(另一个辅助方法 或者 主构造方法)。
// 在 Java 类中,构造方法要么调用同一个类的另一个构造方法,要么直接调用超类的构造方法。
// 而在 Scala 类中,只有主构造方法可以调用超类的构造方法。
// 辅助构造方法
def this(name: String, age: Int) = this(170, name, age, "beijing") // 调用主构造方法
// 辅助构造方法
def this(name: String) = {
this(name, 18) // 首先调用构造方法(辅助构造方法)
// println(name) // 调用构造函数以后可以做其他操作
}
// 使用require函数,不满足则抛出错误
require(age != 0)
// 操作符重载
def +(that: Student): Student = new Student(
height + that.height,
name + "_" + that.name,
age + that.age,
address + "_" + that.getAddress
)
// 覆写 toString 方法, 默认的打印内容
override def toString = height + "-" + name + "-" + age + "-" + address
// 成员方法
def goHome(): Unit = {
println("go home")
}
// 成员方法: 重载了 goHome 方法
def goHome(atTime: String): Unit = {
println("go home at "+ atTime)
}
// 定义了常量,这个常量是的值是一个函数
val gotoSchool: () => Unit = () => {
println("go to school")
}
}
二. 样例类
样例类一般用于不可变对象,并且可作值比较。
- 实例化案例类Book时,并没有使用关键字new,这是因为案例类有一个默认的apply方法来负责对象的创建。
- 创建包含参数的案例类时,这些参数是 public 的 val,在样例类中使用var也是可以的,但并不推荐这样。
- 案例类在比较的时候是按值比较而非按引用比较。
// x和y 是 public val
case class Point(x: Int, y: Int)
// 没有使用关键字new
val point = Point(1, 2)
val anotherPoint = Point(1, 2)
val yetAnotherPoint = Point(2, 2)
// 值比较,而不是引用比较
println(point == anotherPoint) // true
println(anotherPoint == yetAnotherPoint) // false
- 浅拷贝
case class Point(x: Int, y: Int)
val point1 = Point(4, 5)
val point2 = point1
val point3 = point1.copy()
// 比较对象的引用是否相同或者不同,请用eq或ne方法
println(point1.eq(point2)) // true 引用了同一个对象
println(point1.eq(point3)) // false 是两个不同的对象,所以不等
println(point1 == point3) // true 比较的是值,所以相同
// copy 的同时修改某些值
val point4 = point1.copy(y = 9)
三. 单例对象
- 单例对象是一种特殊的类,有且只有一个实例。
- 当一个单例对象和某个类共享一个名称时,这个单例对象称为 伴生对象,这个类被称为是这个单例对象的伴生类。
- 类和它的伴生对象可以互相访问其私有成员。
- 使用伴生对象来定义那些在伴生类中不依赖于实例化对象而存在的成员变量或者方法。相当于Java中的static属性。
package org.example
object Student {
var school = "beijing university"
// main 方法表示执行入口
def main(args: Array[String]): Unit = {
val wang = new Student("wang", 19, "beijing")
println(wang.getDetail) // 访问公有属性
println(wang.height) // 访问私有变量
println(school) // "beijing university"
setSchool("tianjin university")
println(school) // "tianjin university"
}
// 定义其他的 static 方法
def setSchool(name:String): Unit = {
school = name
}
}
class Student(name: String,
age: Int = 18,
address: String) {
private val height: Int = 170
def getDetail = {
name + "-" + age + "-" + address
}
}
四. 特质
特质是包含某些字段和方法的类型。可以组合多个特质。相当于 Java 中的抽象类
- trait 相当于 抽象类。
- 凡是需要特质的地方,都可以由该特质的子类型来替换。
package org.example
trait Iterator[A] {
def hasNext: Boolean
def next(): A
}
class IntIterator(maxNumber: Int) extends Iterator[Int] {
private var current = 0
override def hasNext: Boolean = current < maxNumber
override def next(): Int = {
if (hasNext) {
val t: Int = current
current += 1
t
} else 0
}
}
val iterator = new IntIterator(10)
iterator.next() // returns 0
iterator.next() // returns 1
- 可以使用extends关键字来继承特质,使用override关键字来覆盖默认的实现。
package org.example
trait Greeter {
def greet(name: String): Unit =
println("Hello, " + name + "!")
}
class CustomGreeter extends Greeter {
override def greet(name: String): Unit = {
println("Custom Hello, " + name + "!")
}
}
object CustomGreeter {
def main(args: Array[String]): Unit = {
// greater 的类型 可以是 Greeter 或者 CustomGreeter
val greeter: Greeter = new CustomGreeter()
greeter.greet("wang")
}
}