0%

scala构造器

scala构造器

scala与java相似,也存在构造器,且同样的一个类可以有多个构造器,支持构造器的重载,在构造对象时需要调用构造器,但是与java不同的是scala分为主构造器和辅助构造器

语法

1
2
3
4
5
6
7
8
9
10
11
// 这里的形参列表可以用var|val来修饰,默认是val的,即只读,不过一般没有必要用var
class 类名(形参列表) { // 主构造器
// 类体
// 可以有多个辅助构造器,函数名称都为this,根据不同的参数来区分(java的构造器重载)
def this(形参列表) { // 辅助构造器
// 辅助构造器必须在第一行显式(直接或间接)的调用主构造器
}
def this(形参列表) { //辅助构造器
// 辅助构造器必须在第一行显式(直接或间接)的调用主构造器
}
}

主构造器

主构造器的声明直接放置于类名之后,主构造器会执行类定义中的所有语句,即:构造器也是方法(函数),传递参数和 使用方法和前面的函数部分内容没有区别,主构造器只能有一个,如果没有显式定义主构造器则自动生成一个无参的主构造器

主构造器会执行类体中定义的所有语句

1
2
3
4
5
6
7
8
9
// 如果主构造器没有参数,则()可省略
class Person(var inName: String, val inCardNo: String) { // 主构造器,主构造器只能有一个

private var name:String = inName
private var cardNo:String = inCardNo

println("构造器")

}

编译之后

1
2
3
4
5
public Person(final String inName, final String inCardNo) {
this.name = inName;
this.cardNo = inCardNo;
Predef$.MODULE$.println((Object)"构造器");
}

可以看到class中的所有东西都会变成构造器中的内容

实例化对象

1
val p = new Person("zs","123456")

私有化主构造器

如果主构造器想要进行私有化在参数列表前加上private

1
2
3
4
5
6
7
8
9
10
class Person private(inName: String, inCardNo: String) { // 主构造器,主构造器只能有一个

private var name:String = inName
private var cardNo:String = inCardNo
private var sex:String = _


println("构造器")

}

辅助构造器

辅助构造器是可以有多个的,且辅助构造器的第一行必须显式(直接或间接)的调用主构造器(这里是为了使用主构造器去调用父类的构造器,相当于java中每个构造器第一行都会使用super去调用父类构造器一样)

scala中只有主构造器可以调用父类的构造器,辅助构造器不能直接调用父类的构造器,在构造器中不能使用super()来调用父类构造器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class Person(inName: String, inCardNo: String) { // 主构造器,主构造器只能有一个

private var name:String = inName
private var cardNo:String = inCardNo
private var sex:String = _


println("构造器")

def this(name:String,cardNo:String,sex:String){ // 辅助构造器可以有多个
// 辅助构造器第一行必须显式的调用主构造器
this(name,cardNo)
this.sex = sex
println("辅助构造器")
}

}

编译成java之后

1
2
3
4
5
6
7
8
9
10
11
public Person(final String inName, final String inCardNo) {
this.name = inName;
this.cardNo = inCardNo;
Predef$.MODULE$.println((Object)"构造器");
}

public Person(final String name, final String cardNo, final String sex) {
this(name, cardNo);
this.sex_$eq(sex);
Predef$.MODULE$.println((Object)"辅助构造器");
}

默认的getter/setter方法

举例如

1
2
3
class Person {
var age = 0;
}

在进行字段操作时会调用getter/setter方法,以age字段为例默认的getter和setter方法分别叫做age和age_=

1
2
println(p.age) // 会调用p.age(),反编译的getter方法为public int age()
p.age=20 // 会调用p.age=(20),反编译的setter方法为age_eq$(int),这个eq$就是=,jvm中没有=,所以编译为eq$

也可以重新定义getter/setter方法

1
2
3
4
5
6
7
8
class Person {
private var privateAge = 0

def age = privateAge
def age_=(newValue: Int) {
if(newValue > privateAge) privateAge = newValue;
}
}

调用还是之前的方式

1
2
println(p.age) // 会调用p.age()
p.age=20 // 会调用p.age=(20)
  • 如果字段是私有的,则getter和setter方法也是私有的
  • 如果字段是val,则只生成getter方法
  • 如果不需要getter和setter方法,可以将字段声明为private[this]

Bean

很多的java框架都已经习惯了getter/setter方法的命名习惯了,而scala默认生成的方法java框架是不识别的,为了与java的互操性,scala提供了@BeanProperty来生成getter/setter方法,将scala字段加上@BeanProperty可以像javaBean一样,生成规范的getter/setter方法

1
2
3
4
5
6
7
8
9
10
class Person private(inName: String, inCardNo: String) { // 主构造器,主构造器只能有一个

@BeanProperty var name:String = inName
@BeanProperty var cardNo:String = inCardNo
@BeanProperty var sex:String = _


println("构造器")

}

欢迎关注我的其它发布渠道