# 面向对象
Scala语言是面向对象的
- Java是面向对象的编程语言,由于历史原因,Java中还存在着非面向对象的内容:基本类型 ,null,静态方法等。
- Scala语言来自于Java,所以天生就是面向对象的语言,而且Scala是纯粹的面向对象的语言,即在Scala中,一切皆为对象。
# 1. 类与对象
- 类是抽象的,概念的,代表一类事物,比如人类,猫类..
- 对象是具体的,实际的,代表一个具体事物
- 类是对象的模板,对象是类的一个个体,对应一个实例
- Scala中类和对象的区别和联系 和 Java是一样的。
# 1.1 定义
[修饰符] class 类名 {
类体
}
1
2
3
2
3
# 定义类的注意事项
- Scala语法中,类并不声明为public,所有这些类都具有公有可见性(即默认就是public)
- 一个Scala源文件可以包含多个类.
# 1.2 属性/成员变量
属性是类的一个组成部分,一般是值数据类型,也可是引用类型。
# 注意事项和细节说明
- 属性的定义语法同变量,示例:
[访问修饰符] var 属性名称 [:类型] = 属性值 - 属性的定义类型可以为任意类型,包含值类型或引用类型
- Scala中声明一个属性,必须显示的初始化,然后根据初始化数据的类型自动推断,属性类型可以省略(这点和Java不同)。
- 如果赋值为null,则一定要加类型,因为不加类型, 那么该属性的类型就是Null类型.
- 如果在定义属性时,暂时不赋值,也可以使用符号_(下划线),让系统分配默认值.
| 类型 | _ 对应的值 |
|---|---|
| Byte Short Int Long | 0 |
| Float Double | 0.0 |
| String 和 引用类型 | null |
| Boolean | false |
- 不同对象的属性是独立,互不影响,一个对象对属性的更改,不影响另外一个。这点和java完全一样
# 1.3 方法
Scala中的方法其实就是函数。
def 方法名(参数列表) [:返回值类型] = {
方法体
}
1
2
3
2
3
# 方法的调用机制原理
- 当我们scala开始执行时,先在栈区开辟一个main栈。main栈是最后被销毁
- 当scala程序在执行到一个方法时,总会开一个新的栈。
- 每个栈是独立的空间,变量(基本数据类型)是独立的,相互不影响(引用类型除外)
- 当方法执行完毕后,该方法开辟的栈就会被jvm机回收。
# 1.4 创建对象
val | var 对象名 [:类型] = new 类型()
1
- 如果我们不希望改变对象的引用(即:内存地址), 应该声明为val 性质的,否则声明为var, scala设计者推荐使用val ,因为一般来说,在程序中,我们只是改变对象属性的值,而不是改变对象的引用。
- scala在声明对象变量时,可以根据创建对象的类型自动推断,所以类型声明可以省略,但当类型和后面new 对象类型有继承关系即多态时,就必须写了
# 实例
object OopTest {
def main(args: Array[String]): Unit = {
// 创建对象
// 如果我们不希望改变对象的引用(即:内存地址), 应该声明为val 性质的,否则声明为var
val person: Person = new Person
// scala在声明对象变量时,可以根据创建对象的类型自动推断。所以 :Person可以省略
// 但 当类型和后面 new 对象类型有继承关系即多态时,就必须写了
// val person = new Person
// 属性赋值
person.id = 1
person.name = "leichu"
person.age = 30
person.address = "合肥"
person.del = false
// 调用 say 方法
println(person.say(person.name))
// 调用 toString 方法
println(person)
}
}
class Person {
var id: Long = _ // 暂不赋值,让系统自动赋默认值。使用 _ 时,必须定义出类型。
var name: String = "" // 类型 + 默认值
var age: Int = 0
var address: String = null
var del: Boolean = false
// 定义方法
def say(word: String): String = {
s"hello $word"
}
// 重写父类 toString 方法
override def toString: String = {
s"id: $id \t name: $name \t age: $age \t address: $address \t del: $del"
}
}
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
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
# 2. 构造器
和Java一样,Scala构造对象也需要调用构造方法,并且可以有任意多个构造方法(即scala中构造器也支持重载)。Scala类的构造器包括: 主构造器 和 辅助构造器
class 类名(形参列表) { // 主构造器
// 类体
def this(形参列表) { // 辅助构造器
}
def this(形参列表) { //辅助构造器可以有多个...
}
}
1
2
3
4
5
6
7
2
3
4
5
6
7
# Scala构造器注意事项和细节
- Scala构造器作用是完成对新对象的初始化,构造器没有返回值。
- 主构造器的声明直接放置于类名之后
- 主构造器会执行类定义中的所有语句,这里可以体会到Scala的函数式编程和面向对象编程融合在一起,即:构造器也是方法(函数),传递参数和使用方法和前面的函数部分内容没有区别
- 如果主构造器无参数,小括号可省略,构建对象时调用的构造方法的小括号也可以省略
- 辅助构造器名称为this(这个和Java是不一样的),多个辅助构造器通过不同参数列表进行区分, 在底层就是f构造器重载。
# 实例
object OopTest4Constructor {
def main(args: Array[String]): Unit = {
val user1 = new User(1, "leichu")
val id1 = user1.id
val name1 = user1.name
println(s"id:$id1 name:$name1")
val user2 = new User("leichu")
val id2 = user2.id
val name2 = user2.name
println(s"id:$id2 name:$name2")
}
}
class User(_id: Int) { // 主构造器
var id: Int = _id
var name: String = _
def this(_id: Int, _name: String) { // 辅助构造器
this(_id)
name = _name
}
def this(_name: String) { // 辅助构造器重载
this(0)
name = _name
}
}
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
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
# 2.1 构造器参数
- Scala类的主构造器的形参未用任何修饰符修饰,那么这个参数是局部变量。
- 如果参数使用val关键字声明,那么Scala会将参数作为类的私有的只读属性使用
- 如果参数使用var关键字声明,那么那么Scala会将参数作为类的成员属性使用,并会提供属性对应的
xxx()[类似getter]/xxx_$eq()[类似setter]方法,即这时的成员属性是私有的,但是可读写。
# 反编译前
class User(_id: Int) {
var id: Int = _id
var name: String = _
def this(_id: Int, _name: String) {
this(_id)
name = _name
}
def this(_name: String) {
this(0)
name = _name
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 反编译后
public class User
{
private int id;
private String name;
public void id_$eq(int x$1)
{
this.id = x$1;
}
public User(int _id)
{
this.id = _id;
}
public int id()
{
return this.id;
}
public void name_$eq(String x$1)
{
this.name = x$1;
}
public String name()
{
return this.name;
}
public User(int _id, String _name)
{
this(_id);
name_$eq(_name);
}
public User(String _name)
{
this(0);
name_$eq(_name);
}
}
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
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
# 3. Bean属性
JavaBeans规范定义了Java的属性是像getXxx()和setXxx()的方法。许多Java工具(框架)都依赖这个命名习惯。为了Java的互操作性。将Scala字段加@BeanProperty时,这样会自动生成规范的 setXxx/getXxx 方法。这时可以使用 对象.setXxx() 和 对象.getXxx() 来调用属性。
注意: 给某个属性加入@BeanPropetry注解后,会生成getXXX和setXXX的方法,并且对原来底层自动生成类似xxx(),xxx_$eq()方法,没有冲突,二者可以共存。
# 反编译前
import scala.beans.BeanProperty
object BeanPropertyTest {
def main(args: Array[String]): Unit = {
val student = new Student
student.setName("leichu")
println(student)
}
}
class Student {
var id: Int = _
@BeanProperty var name: String = _
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
2
3
4
5
6
7
8
9
10
11
12
13
14
# 反编译后
public class Student
{
private int id;
private String name;
public void id_$eq(int x$1)
{
this.id = x$1;
}
public int id()
{
return this.id;
}
public void name_$eq(String x$1)
{
this.name = x$1;
}
public String getName()
{
return name();
}
public void setName(String x$1)
{
name_$eq(x$1);
}
public String name()
{
return this.name;
}
}
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
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