scala-类和对象
2017-07-02 19:47
183 查看
http://blog.csdn.net/lovehuangjiaju/article/details/47009607
本节主要内容
1 类定义、创建对象 2 主构造器
3 辅助构造器
类定义、创建对象
//采用关键字class定义 class Person { //类成员必须初始化,否则会报错 //这里定义的是一个公有成员 var name:String=null }1
2
3
4
5
6
1
2
3
4
5
6
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(); }1
2
3
4
5
6
7
8
9
1
2
3
4
5
6
7
8
9
从字节码文件内容可以看到:虽然我们只在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 = jonh1
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; //getter方法 def name=privateName //setter方法 def name_=(name:String){ this.privateName=name } }1
2
3
4
5
6
7
8
9
10
11
12
1
2
3
4
5
6
7
8
9
10
11
12
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
2
3
4
5
6
7
8
9
10
11
12
1
2
3
4
5
6
7
8
9
10
11
12
从生成的字节码中可以看出:(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 = john1
2
3
4
5
6
7
8
9
10
11
12
1
2
3
4
5
6
7
8
9
10
11
12
从代码执行产生的结果,我们可以知道:通过p.name=“john”这种方式进行赋值,调用者并不需要知道是其通过方法调用还是字段访问来进行操作的,这便是著名的统一访问原则
如果类的成员域是val类型的变量,则只会生成getter方法
class Person { //类成员必须初始化,否则会报错 //这里定义的是一个val公有成员 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(); }1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
从字节码文件中可以看出:val变量对应的是java中的final类型变量,只生成了getter方法
如果将成员域定义为private[this],则不会生成getter、setter方法
class Person { //类成员必须初始化,否则会报错 //private[this]修饰 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(); }1
2
3
4
5
6
7
8
9
10
11
12
13
14
1
2
3
4
5
6
7
8
9
10
11
12
13
14
在java语言当中,在定义JavaBean的时候生成的都是setXxx()、getXxx()方法,但scala语言生成的getter方法和setter方法并不是这样的,如果也需要程序自动会生成getter方法和setter方法,则需要引入
scala.reflect.BeanProperty
然后采用注解的方式修饰变量
class Person { //类成员必须初始化,否则会报错 //@BeanProperty用于生成getXxx,setXxx方法 @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
类主构造器
主构造器的定义与类的定义交织在一直,将构造器参数直接放在类名称之后,如下代码://下列代码不但定义了一个类Person,还定义了主构造器,主构造器的参数为String、Int类型 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); } //不难看出:上面的代码与下列java语言编写的代码等同 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 = 291
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将作为主构建器中的一部分,在创建对象时被执行 println("constructing Person ........") //重写toString()方法 override def toString()= name + ":"+ age } scala> val p=new Person("john",29) constructing Person ........ p: Person = john:291
2
3
4
5
6
7
8
9
10
11
12
1
2
3
4
5
6
7
8
9
10
11
12
回过头来看的话,前面我们定义的Person类是一种无参主构建器
//Person类具有无参主构建器 class Person { println("constructing Person....") val name:String="john" } scala> val p=new Person() constructing Person.... p: Person = Person@79895f1
2
3
4
5
6
7
8
9
10
1
2
3
4
5
6
7
8
9
10
主构建器还可以使用默认参数
//默认参数的主构建器 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:181
2
3
4
5
6
7
8
9
10
11
12
13
14
1
2
3
4
5
6
7
8
9
10
11
12
13
14
主构造器中的参数还可以加访问控制符
//默认参数的主构建器,参数带访问控制符号 //age变成私有成员,其getter方法是私有的,外部不能访问 class Person(val name:String="",private val age:Int=18){ println("constructing Person ........") override def toString()= name + ":"+ age }1
2
3
4
5
6
7
1
2
3
4
5
6
7
当主构造器的参数不用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
在某些情况下,可能需要禁用主构建器,代码如下:
//类名后面紧跟private关键字可以将主构建器设为私有,不允许外部使用 class Person private(var name:String,var age:Int){ println("constructing Person ........") } //生成的字节码文件如下,可以看到其构建函数已经为private了 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)//此处会发生编译错误,这是因为def this(name:String,age:Int)没有被定义 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类
//具有主构建函数和辅助构建函数的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); }
相关文章推荐
- IBM scala(一)-----面对对象的函数编程
- 【Scala】Scala的Predef对象
- scala 类和对象
- Scala坑五(类和对象)
- 云星数据---Scala实战系列(精品版)】:Scala入门教程031-Scala实战源码-Scala 对象 01
- Scala简史 对象函数式编程
- 2016 第2讲 Scala面向对象彻底精通及Spark源码阅读
- Scala初体验之:实例化对象
- Step into Scala - 12 - 对象与枚举
- Scala深入浅出进阶经典 第64讲:Scala中隐式对象代码实战详解
- Scala之旅-面向对象
- scala 学习笔记(04) OOP(上)主从构造器/私有属性/伴生对象(单例静态类)/apply方法/嵌套类
- Scala 深入浅出实战经典 第7讲:Scala类的属性和对象私有字段实战详解
- scala的类和对象
- DT大数据 scala 单例 伴生对象
- scala 开发入门(5)-- 类与对象
- Scala系列学习及应用(Object对象)
- Scala的Predef对象
- Scala伴生类和伴生对象
- Scala的单例对象