一.本章要点
- 类中的字段自动带有getter方法和setter方法
- 你可以用定制的getter/setter方法替换掉字段的定义,而不必修改使用类的客户端——这就是所谓的”统一访问原则“
- 用@BeanProperty注解来生成JavaBean的getXxx/setXxx方法
- 每个类都有一个主要的构造器,这个构造器和类定义”交织“在一起。它的参数直接称为类的字段。主构造器执行类体中所有的语句
- 辅助构造器是可选的。它们叫做this
二.简单类和无参方法
Class Counter{ private var value=0 //你必须初始化字段 def increment(){ value=+1}// 方法默认是共有的 def current=value //可以用不带()的方式强制风格 }
注:调用无参方法时,可以写上(),也可以不写,这里有一种风格(对于改值器方法[改变对象状态的方法]使用(),而对于取值器方法[不会改变对象状态的方法]去掉())
三.带getter和setter的属性
Scala为每个字段都提供getter和setter方法 (gettter和setter分别对应xxx和xxx_)。
注:
-
-
- 如果字段是私有的,则getter和setter方法也是私有的;
- 如果字段是val,则只有getter方法被生成;
- 如果你不需要仍个getter和setter,可以将字段声明为private[this]
-
四.只带getter的属性
有时候你需要一个只读属性,有getter但没有setter,则可以使用val字段,这样Scala会生成一个私有的final字段和一个getter方法。
注:
通过这种方式客户端不能任意改值,但如果需要可以通过其他方式根据自己的需求改变,且在Scala中不能实现只写属性,例:
class Counter{ private var value=0 def increment(){value+=1} def current=value }
小结:
-
-
- var foo:Scala会自动合成一个getter和setter
- val foo:Scala自动合成一个getter
- 由你来定义foo和foo_=方法
- 由你来定义foo方法
-
五.对象私有字段
在Scala中,和Java/C++等一样,方法可以访问所有对象的私有字段,例:
Class Counter{ private var value=0 de increment(){value+=1} def isLess(other:Counter)=value<other.value //同样可以访问另一个对象的私有字段 }
于是Scala允许我们定义更严格的访问限制,通过private[this]修饰符来实现。(private[this] var value=0 //类似某个对象.value这样的访问将不被允许,因此Counter类的方法只能访问当前对象的value字段,而不能访问同样是Counter类型的其他对象的字段,这样的访问有时被称为对象私有的[对于对象私有的字段,Scala根本不会生成getter和setter方法])。
注:Scala允许你将访问权赋予指定的类,private[类名]修饰符可以定义仅有指定类的方法可以访问给定的字段。这里的类名必须是当前定义的类或者是包含该类的外部类。
六.Bean属性
Scala会对定义的字段提供setter和getter方法,但是这些名称都不是预期的(Java工具依赖于setFoo和getFoo这样的命名)。使用@BeanProperty会自动生成四个方法,例子:
impoer scala.reflect.BeanProperty class Person{ @BeanProperty var name:String=_ }
提供的四个方法:
1.name:String;
2.name_=(new Value:String):Unit;
3.getName():String;
4.setName(new Value:String):Unit
七.辅助构造器
Scala和Java一样,可以有任意多个构造器(一个主构造器[重要]多个辅助构造器)。
注意(构造器与Java/C++不同点):
1.辅助构造器的名称是this(而不像Java中与类名相同);
2.每一个辅助构造器都必须以一个对先前已经定义的其他辅助构造器或主构造器的调用开始
例:
class Person{ private var name="" private var age=0 def this(name:String){ //一个辅助构造器 this()//调用主构造器 } def this(name:String,age:Int){ this(name) //调用前一个辅助构造器 this.age=age } }
八.主构造器
如果没有显式定义主构造器,则自动拥有一个无参的主构造器(简单的执行类体中的所有语句而已)。
要点:
1.主构造器的参数直接放置在类名之后:
class Person(val name:String,val age:Int){ }
2.主构造器会执行类定义中的所有语句(如配置某个字段的特性时非常有用)
class MyProg{ private val props=new Properties props.load(new FileReader("myprog.properties")) //上述语句是主构造器的一部分 }
注:
主构造器的参数可以是任意形态的,如private,val,var的;
也可以是普通的方法参数(不加val/var),这样的参数如何处理取决于它们在类中如何被使用,如:
1.不带val/var的参数至少被一个方法使用,则升格为字段,类似于private[this] val字段的效果;
2.否则,该参数不被保存为字段(仅仅是可以被主构造器访问的普通参数)
如果想把构造器变成私有的,可以calss Person private(val id:Int){...}
九.嵌套类
Scala中,几乎可以任何语法结构嵌套任何语法结构(函数中嵌套函数,类中嵌套类)
import scala.collection.mutable.ArrayBuffer class Network{ class Member(val name:String){ val contacts=new ArrayBuffer[Member] } private val members=new ArrayBuffer[Member] def join(name:sSring)={ val m=new Member(name) member+=m m } }
每个实例对象都有自己的Member类,这和Java不同(Java的内部类从属于外部类)。
每个实例只能在各自中添加成员,而不能跨实例。
如果不希望是上图那样,可以使用伴生对象或者类型投影:
伴生对象
类型投影
建立引用别名
十.练习