本节主要内容
1 类定义、创建对象
2 主构造器
3 辅助构造器
类定义、创建对象
class Person {
var name:String=null
}
Person类在编译后会生成Person.class文件
利用javap -prviate Person命令查看字节码文件内容,可以看得到以下内容
D:\ScalaWorkspace\ScalaChapter06\bin\cn\scala\xtwy>javap -private Person
警告: 二进制文件Person包含cn.scala.xtwy.Person
Compiled from "Person.scala"
public class cn.scala.xtwy.Person {
private java.lang.String name;
public java.lang.String name();
public void name_$eq(java.lang.String);
public cn.scala.xtwy.Person();
}
从字节码文件内容可以看到:虽然我们只在Person类中定义了一个类成员(域)name,类型为String,但Scala会默认帮我们生成name()与name_=()及构造函数Person()。其中name()对应Java中的getter方法,name_=()对应java中的setter方法(由于JVM中不允许出现=,所以用$eq代替。值得注意的是定义的是公有成员,但生成的字节码中却是以私有的方式实现的,生成的getter、setter方法是公有的
因此,可以直接new操作创建Person对象
//默认已经有构建函数,所以可以直接new
scala> val p=new Person()
p: Person = Person@84c504
//直接调用getter和setter方法
//setter方法
scala> p.name_=("john")
//getter方法
scala> p.name
res2: String = john
//直接修改,但其实调用的是p.name_=("jonh")
scala> p.name="jonh"
p.name: String = jonh
//getter方法
scala> p.name
res28: String = jonh
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
你也可以定义自己的getter和setter方法
class Person{
private var privateName:String=null;
def name=privateName
def name_=(name:String){
this.privateName=name
}
}
D:\ScalaWorkspace\ScalaChapter06\bin\cn\scala\xtwy>javap -private Person
警告: 二进制文件Person包含cn.scala.xtwy.Person
Compiled from "Person.scala"
public class cn.scala.xtwy.Person {
private java.lang.String privateName;
private java.lang.String privateName();
private void privateName_$eq(java.lang.String);
public java.lang.String name();
public void name_$eq(java.lang.String);
public cn.scala.xtwy.Person();
}
从生成的字节码中可以看出:(1)定义成私有成员,其getter、setter方法也是私有的;(2)直接能访问的是我们自己定义的getter、setter方法。下面给出的是调用方式
scala> val p=new Person()
p: Person = Person@12d0b54
scala> p.name
res29: String = null
//直接赋值法
scala> p.name="john"
p.name: String = john
scala> p.name
res30: String = john
从代码执行产生的结果,我们可以知道:通过p.name=“john”这种方式进行赋值,调用者并不需要知道是其通过方法调用还是字段访问来进行操作的,这便是著名的统一访问原则
如果类的成员域是val类型的变量,则只会生成getter方法
class Person {
val name:String="john"
}
D:\ScalaWorkspace\ScalaChapter06\bin\cn\scala\xtwy>javap -private Person
警告: 二进制文件Person包含cn.scala.xtwy.Person
Compiled from "Person.scala"
public class cn.scala.xtwy.Person {
private final java.lang.String name;
public java.lang.String name();
public cn.scala.xtwy.Person();
}
从字节码文件中可以看出:val变量对应的是java中的final类型变量,只生成了getter方法
如果将成员域定义为private[this],则不会生成getter、setter方法
class Person {
private[this] var name:String="john"
}
D:\ScalaWorkspace\ScalaChapter06\bin\cn\scala\xtwy>javap -private Person
警告: 二进制文件Person包含cn.scala.xtwy.Person
Compiled from "Person.scala"
public class cn.scala.xtwy.Person {
private java.lang.String name;
public cn.scala.xtwy.Person();
}
在java语言当中,在定义JavaBean的时候生成的都是setXxx()、getXxx()方法,但scala语言生成的getter方法和setter方法并不是这样的,如果也需要程序自动会生成getter方法和setter方法,则需要引入 scala.reflect.BeanProperty
然后采用注解的方式修饰变量
class Person {
@BeanProperty var name:String="john"
}
D:\ScalaWorkspace\ScalaChapter06\bin\cn\scala\xtwy>javap -private Person
警告: 二进制文件Person包含cn.scala.xtwy.Person
Compiled from "Person.scala"
public class cn.scala.xtwy.Person {
private java.lang.String name;
public java.lang.String name();
public void name_$eq(java.lang.String);
public void setName(java.lang.String);
public java.lang.String getName();
public cn.scala.xtwy.Person();
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
下图给出的是getter、setter方法产生的规则
来源:scala for the impatient
类主构造器
主构造器的定义与类的定义交织在一直,将构造器参数直接放在类名称之后,如下代码:
class Person(val name:String,val age:Int)
D:\ScalaWorkspace\ScalaChapter06\bin\cn\scala\xtwy>javap -private Person
警告: 二进制文件Person包含cn.scala.xtwy.Person
Compiled from "Person.scala"
public class cn.scala.xtwy.Person {
private final java.lang.String name;
private final int age;
public java.lang.String name();
public int age();
public cn.scala.xtwy.Person(java.lang.String, int);
}
public class Person{
private final String name;
private final int age;
public Person(String name,int age){
this.name=name;
this.age=age;
}
public String getName(){ return name}
public int getAge() {return age}
}
scala> val p=new Person("john",29)
p: Person = Person@abdc0f
scala> p.name
res31: String = john
scala> p.age
res32: Int = 29
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
主构造器会执行类定义中的所有语句,例如
class Person(val name:String,val age:Int){
println("constructing Person ........")
override def toString()= name + ":"+ age
}
scala> val p=new Person("john",29)
constructing Person ........
p: Person = john:29
回过头来看的话,前面我们定义的Person类是一种无参主构建器
class Person {
println("constructing Person....")
val name:String="john"
}
scala> val p=new Person()
constructing Person....
p: Person = Person@79895f
主构建器还可以使用默认参数
class Person(val name:String="",val age:Int=18){
println("constructing Person ........")
override def toString()= name + ":"+ age
}
scala> val p=new Person
constructing Person ........
p: Person = :18
scala> val p=new Person("john")
constructing Person ........
p: Person = john:18
主构造器中的参数还可以加访问控制符
class Person(val name:String="",private val age:Int=18){
println("constructing Person ........")
override def toString()= name + ":"+ age
}
当主构造器的参数不用var或val修饰的时候,参数会生成类的私有val成员,并且不会产生getter和setter方法
class Person(name:String,age:Int){
println("constructing Person ........")
override def toString()= name + ":"+ age
}
D:\ScalaWorkspace\ScalaChapter06\bin\cn\scala\xtwy>javap -private Person
警告: 二进制文件Person包含cn.scala.xtwy.Person
Compiled from "Person.scala"
public class cn.scala.xtwy.Person {
private final java.lang.String name;
private final int age;
public java.lang.String toString();
public cn.scala.xtwy.Person(java.lang.String, int);
}
class Person(private[this] val name:String,private[this] val age:Int){
println("constructing Person ........")
override def toString()= name + ":"+ age
}
D:\ScalaWorkspace\ScalaChapter06\bin\cn\scala\xtwy>javap -private Person
警告: 二进制文件Person包含cn.scala.xtwy.Person
Compiled from "Person.scala"
public class cn.scala.xtwy.Person {
private final java.lang.String name;
private final int age;
public java.lang.String toString();
public cn.scala.xtwy.Person(java.lang.String, int);
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
值得注意的是,将上述Person类中的toString()方法去掉,则类中无任何地方使用了主构造器的参数,此时主构造器参数不会生成类成员
即将
class Person(name:String,age:Int){
println("constructing Person ........")
override def toString()= name + ":"+ age
}
改成:
class Person( val name:String,age:Int){
println("constructing Person ........")
}
其字节码文件如下:
D:\ScalaWorkspace\ScalaChapter06\bin\cn\scala\xtwy>javap -private Person
警告: 二进制文件Person包含cn.scala.xtwy.Person
Compiled from "Person.scala"
public class cn.scala.xtwy.Person {
public cn.scala.xtwy.Person(java.lang.String, int);
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
下面图给出了Scala中主构建器参数生成类成员和方法时的规则
来源:scala for the impatient
在某些情况下,可能需要禁用主构建器,代码如下:
class Person private(var name:String,var age:Int){
println("constructing Person ........")
}
D:\ScalaWorkspace\ScalaChapter06\bin\cn\scala\xtwy>javap -private Person
警告: 二进制文件Person包含cn.scala.xtwy.Person
Compiled from "Person.scala"
public class cn.scala.xtwy.Person {
private java.lang.String name;
private int age;
public java.lang.String name();
public void name_$eq(java.lang.String);
public int age();
public void age_$eq(int);
private cn.scala.xtwy.Person(java.lang.String, int);
}
scala> val p=new Person("john",19)
<console>:9: error: constructor Person in class Person cannot be accessed in obj
ect $iw
val p=new Person("john",19)
^
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
辅助构造函数
前面讲了,如果禁用掉了主构建器,则必须使用辅助构造函数来创建对象。辅助构造函数具有两个特点:(1)辅助构建器的名称为this,java中的辅助构造函数与类名相同,这常常会导致修改类名时出现不少问题,scala语言避免了这样的问题;(2)调用辅助构造函数时,必须先调用主构造函数或其它已经定义好的构造函数。
3.1 我们首先看一下只有辅助构造函数的Person类
class Person{
private var name:String=null
private var age:Int=18
private var sex:Int=0
def this(name:String){
this()
this.name=name
}
def this(name:String,age:Int){
this(name)
this.age=age
}
def this(name:String,age:Int,sex:Int){
this(name,age)
this.sex=sex
}
}
D:\ScalaWorkspace\ScalaChapter06\bin\cn\scala\xtwy>javap -private Person
警告: 二进制文件Person包含cn.scala.xtwy.Person
Compiled from "Person.scala"
public class cn.scala.xtwy.Person {
private java.lang.String name;
private int age;
private int sex;
private java.lang.String name();
private void name_$eq(java.lang.String);
private int age();
private void age_$eq(int);
private int sex();
private void sex_$eq(int);
public cn.scala.xtwy.Person();
public cn.scala.xtwy.Person(java.lang.String);
public cn.scala.xtwy.Person(java.lang.String, int);
public cn.scala.xtwy.Person(java.lang.String, int, int);
}
class Person{
private var name:String=null
private var age:Int=18
private var sex:Int=0
def this(name:String,age:Int,sex:Int){
this(name,age)
this.sex=sex
}
def this(name:String){
this()
this.name=name
}
def this(name:String,age:Int){
this(name)
this.age=age
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
3.2 带主构造函数、辅助构造函数的Person类
class Person(var name:String,var age:Int){
private var sex:Int=0
def this(name:String,age:Int,sex:Int){
this(name,age)
this.sex=sex
}
}
生成的字节码文件如下:
D:\ScalaWorkspace\ScalaChapter06\bin\cn\scala\xtwy>javap -private Person
警告: 二进制文件Person包含cn.scala.xtwy.Person
Compiled from "Person.scala"
public class cn.scala.xtwy.Person {
private java.lang.String name;
private int age;
private int sex;
public java.lang.String name();
public void name_$eq(java.lang.String);
public int age();
public void age_$eq(int);
private int sex();
private void sex_$eq(int);
public cn.scala.xtwy.Person(java.lang.String, int);
public cn.scala.xtwy.Person(java.lang.String, int, int);
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
在主构造函数小节当中我们提到,有时候可能会禁用掉主构造函数,此时只能通过辅助构造函数来创建对象
class Person private(var name:String,var age:Int){
private var sex:Int=0
def this(name:String,age:Int,sex:Int){
this(name,age)
this.sex=sex
}
}
D:\ScalaWorkspace\ScalaChapter06\bin\cn\scala\xtwy>javap -private Person
警告: 二进制文件Person包含cn.scala.xtwy.Person
Compiled from "Person.scala"
public class cn.scala.xtwy.Person {
private java.lang.String name;
private int age;
private int sex;
public java.lang.String name();
public void name_$eq(java.lang.String);
public int age();
public void age_$eq(int);
private int sex();
private void sex_$eq(int);
private cn.scala.xtwy.Person(java.lang.String, int);
public cn.scala.xtwy.Person(java.lang.String, int, int);
}