本文scala使用的版本是2.11.7
第五章 类
5.1 基本操作
class Person {
// Scala会生成一个私有的final字段和一个getter方法,但没有setter
val timeStamp = new java.util.Date
// 必须初始化字段
private var privateAge = 0
def increment() {
privateAge += 1
}
// 方法默认是公有的
def current() = privateAge
// 自定义age的getter方法
def age = privateAge
// 自定义age的setter方法
def age_= (newValue: Int) {
if (newValue > privateAge) privateAge = newValue
}
}
object Note1 extends App {
val fred = new Person
fred.age = 20
println(fred.age)
fred.age = 12
println(fred.age)
}
5.2 对象私有字段
在Scala(Java和C++也一样)中,方法可以访问该类的所有对象的私有字段,例如:
class Counter {
private var value = 0
// 可以访问另一个对象的私有字段
def isLess(other: Counter) = value < other.value
// 类似某个对象.value2这样的访问将不被允许
// 此时Scala不会生成getter和setter方法
private[this] var value2 = 0
}
5.3 Bean属性
import scala.reflect.BeanProperty
class Person {
@BeanProperty var name: String = _
}
Scala字段 | 生成的方法 | 何时使用 |
---|---|---|
val/var name | 公有的name name_=(仅限var) |
实现一个可以被公开访问并背后是以字段形式保存的属性 |
@BeanProperty val/var name | 公有的name getName() name_=(仅限于var) setName(…)(仅限于var) |
与JavaBean互操作 |
private val/var name | 私有的name name_=(仅限于var) |
用于将字段访问限制在本类的方法 |
private[this] val/var name | 无 | 用于将字段访问限制在同一个对象上调用的方法 |
private[类名] val/var name | 依赖于具体实现 | 将访问权赋予外部类 |
5.4 构造器
辅助构造器
- 辅助构造器的名称为this
- 每一个辅助构造器都必须以一个对先前已定义的其他辅助构造器或主构造器的调用开始
class Person {
private var name = ""
private var age = 0
def this(name: String) {
this // 调用主构造器
this.name = name
}
def this(name: String, age: Int) {
this(name)
this.age = age
}
}
主构造器
主构造器的参数直接放置在类名之后
class Person(val name: String, private var age: Int, addr: String) // 如果不带val或var的参数(例如addr)至少被一个方法所使用,它将被升格为字段。类似这样的字段等同于private[this] val字段效果。
主构造器会执行类定义中的所有语句
class Person(val name: String, val age: Int) { println("创建Person对象") def desc = name + " is " + age + " years old" } // 上面的println就会被执行
5.5 嵌套类
在Scala中,几乎可以在任何语法结构中内嵌任何语法结构。
class Network {
class Member {
}
}
5.6 习题解答
http://ivaneye.iteye.com/blog/1829957
1. 改进5.1节的Counter类,让它不要在Int.MaxValue时变成负数
class Counter {
private var value = 0
def increment() { if (value < Int.MaxValue) value += 1 }
def current = value
}
val myCounter = new Counter
myCounter.increment
println(myCounter.current)
2. 编写一个BankAccount类,加入deposit和withdraw方法,和一个只读的balance属性
class BankAcount(val balance : Int = 0) {
def deposit() {}
def withdraw() {}
}
3. 编写一个Time类,加入只读属性hours和minutes,和一个检查某一时刻是否早于另一时刻的方法before(other:Time):Boolean。Time对象应该以new Time(hrs,min)方式构建。其中hrs以军用时间格式呈现(介于0和23之间)
class Time(val hours : Int, val minutes : Int) {
def before(other : Time) : Boolean = {
this.hours < other.hours || (this.hours == other.hours && this.minutes < other.minutes)
}
}
val fir = new Time(10, 30)
val sec = new Time(10, 50)
val thi = new Time(12, 10)
sec.before(fir)
sec.before(thi)
4. 重新实现前一个类中的Time类,将内部呈现改成午夜起的分钟数(介于0到24*60-1之间)。不要改变公有接口。也就是说,客户端代码不应因你的修改而受影响
class Time(val hours : Int, val minutes : Int) {
private val innerValue = hours * 60 + minutes;
def before(other : Time) : Boolean = {
this.innerValue < other.innerValue
}
}
val fir = new Time(10, 30)
val sec = new Time(10, 50)
val thi = new Time(12, 10)
sec.before(fir)
sec.before(thi)
5. 创建一个Student类,加入可读写的JavaBeans属性name(类型为String)和id(类型为Long)。有哪些方法被生产?(用javap查看。)你可以在Scala中调用JavaBeans的getter和setter方法吗?应该这样做吗?
import scala.beans.BeanProperty
class Student{
@BeanProperty var name:String = _
@BeanProperty var id:Long = _
}
6. 在5.2节的Person类中提供一个主构造器,将负年龄转换为0
class Person(var age:Int){
age = if(age < 0) 0 else age
}
7. 编写一个Person类,其主构造器接受一个字符串,该字符串包含名字,空格和姓,如new Person(“Fred Smith”)。提供只读属性firstName和lastName。主构造器参数应该是var,val还是普通参数?为什么?
必须为val。如果为var,则对应的此字符串有get和set方法,而Person中的firstName和lastName为只读的,所以不能重复赋值。如果为var则会重复赋值而报错