scala:类
Scala原文件可以包含多个类,类并不显示声明为public
,默认为public
。
类中成员变量:
定义不加private
前缀成员变量的情况:
class T {
var i = 1
}
相当于
public class T{
private int i = 1;
public int i() return this.i;
public void i_$eq(int i) this.i = i;
}
----------------------------------------------
class T {
val i = 1
}
相当于
public class T{
private final int i = 1;
public int i() return this.i;
}
Scala类为每个字段自动生成getter和setter方法(对var变量)或getter方法(对val常量)。
为字段i
自动生成的getter方法名为i
,如下调用:
val t = new T
t.i //不能用t.i(),可以理解为方法定义为def i = i而非def i() = i
为字段i
自动生成的setter方法名为i_=(i:Int)
,如下调用:
t.i = 2 //或
t.i_=(2)
Scala类中所有字段都是私有的。
定义加private
前缀成员变量的情况:
class T {
private var i = 1
}
相当于
public class T{
private int i = 1;
private int i() return this.i;
private void i_$eq(int i) this.i = i;
}
自动生成的getter和setter方法也为private
,其他同不加private
时相同(val常量不生成setter方法。)。
定义加private[this]
前缀成员变量的情况:
class T {
private[this] var i = 1
}
相当于
public class T{
private int i = 1;
}
不自动生成任何getter和setter方法(无论val常量还是var变量)。这种情况下只有对象内部能访问成员变量,称为对象私有的。
Java中的private
并不表示对象私有,而是类私有,也就是说同一个类中的不同对象能够访问彼此间的private
成员。
定义加private[外部类]
前缀成员变量的情况:
class Outer{
class T {
private[Outer] val i = 1
}
println((new T).i)
}
相当于
public class Outer{
public Outer(){
Predef..MODULE$.println(BoxesRunTime.boxToInteger(new Outer.T(this).Outer$$i()));
}
public class T{
private final int Outer$$i = 1;
public int Outer$$i(){
return this.Outer$$i;
}
}
}
这时候内部类T虽然生成了public
的getter方法(由于是val常量,所以没有生成setter),但此方法只有private[外部类]
中指定的外部类Outer
中可以访问。
用BeanProperty
生成Java形式的getter和setter方法
import scala.beans.BeanProperty
class T {
@BeanProperty var i = 1
}
相当于
public class T{
private int i = 1;
public int i() return this.i;
public void i_$eq(int x$1) this.i = x$1;
public void setI(int x$1) this.i = x$1;
public int getI() return i();
}
加入BeanProperty
后,除了会额外生成java形式的getter和setter方法以外,其他方面和上面讲的一样。(BeanProperty
和private
不能同时使用,与private[...]
可以)。
类中构造方法:
Scala类的构造器名字为this
。默认有个无参数的主构造器,若定义辅助构造器则每一个辅助构造器必须以一个先前定义的其他辅助构造器或者主构造器的调用开始。
主构造器
主构造器的定义和类本身交织在一起,看例子:
class T(private[this] val i:Int) {
println(i)
}
相当于
public class T{
public T(int i){
Predef..MODULE$.println(BoxesRunTime.boxToInteger(i));
}
}
也就是说,主构造器的参数直接放到类名之后,并且主构造器会执行类定义中的所有语句。
再看如下:
class T(private val i:Int) {
}
相当于
public class T{
private final int i;
private int i() return this.i;
}
class T(var i:Int) {
}
相当于
public class T{
private int i;
public int i() return this.i;
public void i_$eq(int i) this.i = i;
}
也就是说,Scala会视情况(具体情况同类中成员变量一样)将类主构造器中的参数编译为成员变量(其值被初始化为构造器调用时传入的实参值)。
构造器也可以不带val或var,如下:
class T(i:Int, n:Int) {
println(n)
def f = i
}
相当于
public class T{
private final int i;
public T(int i, int n) {
Predef..MODULE$.println(BoxesRunTime.boxToInteger(n));
}
}
也就是说,如果构造器中参数没有val或var,则Scala这样处理:若参数被至少一个方法所使用(上例中i),它将被提升为成员变量,且是对象私有的(相当于加了private[this] val
的效果)。若没被任何一个方法所使用(上例中n),则参数不被保存为字段,它仅仅是一个可以被主构造方法访问的普通参数。
辅助构造器
class T() {
def this(i:Int) = {
this() //调用主构造器(也可以调用其他已经定义好的辅助构造器)
}
}
相当于
public class T{
public T(){}
public T(int i){}
}
辅助构造器的参数不能加val或var,也不会被编译为成员变量。
如下可以把主构造器变为私有,这样类用户就必须通过辅助构造器来构造对象了:
class T private() {
def this(i:Int) = this()
}
相当于
public class T{
private T(){}
public T(int i){}
}
主构造器中可以定义默认参数:
class T(val i:Int = 2) {
}
这样的话若用new T
构造i
就为2, 用new T(3)构造i就为3,这样可以避免过多的使用辅助构造器。