面向对象
# 面向对象
# 包
# 嵌套声明包
Scala 有两种包的管理风格,其中一种方式和 Java 的包管理风格相同,还有一种是嵌套声明
package com{
package atguigu{
package scala{
}
}
}
2
3
4
5
6
7
第二种风格有以下特点:
- 一个源文件中可以声明多个 package
- 子包中的类可以直接访问父包中的内容,而无需导包
package com {
import com.atguigu.Inner //父包访问子包需要导包
object Outer {
val out: String = "out"
def main(args: Array[String]): Unit = {
println(Inner.in)
}
}
package atguigu {
object Inner {
val in: String = "in"
def main(args: Array[String]): Unit = {
println(Outer.out) //子包访问父包无需导包
}
}
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# 包对象
在 Scala 中可以为每个包定义一个同名的包对象,定义在包对象中的成员,作为其对应包下所有 class 和 object 的共享变量,可以被直接访问。
package object com{
val shareValue="share"
def shareMethod()={}
}
2
3
4
嵌套方式管理包,则包对象可与包定义在同一文件中,但是要保证包对象与包声明在同一作用域中。
package com {
object Outer {
val out: String = "out"
def main(args: Array[String]): Unit = {
println(name)
}
}
}
package object com {
val name: String = "com"
}
2
3
4
5
6
7
8
9
10
11
12
13
14
# 导包
- 和 Java 一样,可以在顶部使用 import 导入,在这个文件中的所有类都可以使用。
- 局部导入:什么时候使用,什么时候导入。在其作用范围内都可以使用
- 通配符导入:import java.util._
- 给类起名:import java.util.{ArrayList=>JL}
- 屏蔽类:import java.util.{ArrayList =>,}
- 导入相同包的多个类:import java.util.{HashSet, ArrayList}
- 导入包的绝对路径:new
_root_.java.util.HashMap
| import com.atguigu.Fruit | 引入 com.atguigu 包下 Fruit(class 和 object) |
|---|---|
| import com.atguigu._ | 引入 com.atguigu 下的所有成员 |
| import com.atguigu.Fruit._ | 引入 Fruit (object) 的所有成员 |
| import com.atguigu.{Fruit,Vegetable} | 引入 com.atguigu 下的 Fruit 和 Vegetable |
| import com.atguigu.{Fruit=>Shuiguo} | 引入 com.atguigu 包下的 Fruit 并更名为 Shuiguo |
| import com.atguigu.{Fruit=>Shuiguo,_} | 引入 com.atguigu 包下的所有成员,并将 Fruit 更名为 Shuiguo |
| import com.atguigu.{Fruit=>,} | 引入 com.atguigu 包下屏蔽 Fruit 类 |
new _root_.java.util.HashMap | 引入的 Java 的绝对路径 |
# 类和对象
类:可以看成一个模板
对象:表示具体的事物
# 定义类
一般,一个.java 有一个 public 类
Scala 中没有 public,一个.scala 中可以写多个类。
- Scala 语法中,类并不声明为 public,所有这些类都具有公有可见性(即默认就是 public)
- 一个 Scala 源文件可以包含多个类
object code05 {
def main(args: Array[String]): Unit = {
val student = new Student05
println(student.name)
}
}
class Student05{
var name = "zhangsan"
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 属性和封装
底层生成的字节码文件对属性使用的是 private 进行修饰,我们通过对象。属性名调用的是 java 中方法,方法名为属性名()即 getXxx()方法

如果想要实现 JavaBean 规范的 get|set 方法需要要属性上加 @BeanPropetry 注解 可以自动生成规范的 setXxx/getXxx 方法
object code05 {
def main(args: Array[String]): Unit = {
val student = new Student05
println(student.age)
}
}
class Student05{
var height: Int = _ // _表示给属性一个该类型的默认值
@BeanProperty
var age = 18
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
val 修饰的属性不能赋默认值,必须显示指定值
val height: Int = _ //此时被赋值为0 无法再次修改

如果在属性前加上 private 关键字 不光属性被私有连方法都会被私有
private var name = "zhangsan"

# 访问权限
在 Java 中,访问权限分为:public,private,protected 和默认。在 Scala 中,你可以通过类似的修饰符达到同样的效果。但是使用上有区别。
- Scala 中属性和方法的默认访问权限为 public,但 Scala 中无 public 关键字。
- private 为私有权限,只在类的内部和伴生对象中可用。
- protected 为受保护权限,Scala 中受保护权限比 Java 中更严格,同类、子类可以访问,同包无法访问。
- private [包名] 增加包访问权限,包名下的其他类也可以使用
package com.atguigu.scala.test
class Person {
private var name: String = "bobo"
protected var age: Int = 18
private[test] var sex: String = "男"
def say(): Unit = {
println(name)
}
}
object Person {
def main(args: Array[String]): Unit = {
val person = new Person
person.say()
println(person.name)
println(person.age)
}
}
class Teacher extends Person {
def test(): Unit = {
this.age
this.sex
}
}
class Animal {
def test: Unit = {
new Person().sex
}
}
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
# 构造器
和 Java 一样,Scala 构造对象也需要调用构造方法,并且可以有任意多个构造方法。
Scala 类的构造器包括:主构造器和辅助构造器
class 类名(形参列表) {
// 主构造器 就在这个类中
// 类体
def this(形参列表) { // 辅助构造器
}
def this(形参列表) { //辅助构造器可以有多个...
}
}
2
3
4
5
6
7
8
9
10
- 辅助构造器,函数的名称 this,可以有多个,编译器通过参数的个数及类型来区分。
- 辅助构造方法不能直接构建对象,必须直接或者间接调用主构造方法。
- 构造器调用其他另外的构造器,要求被调用构造器必须提前声明。
//(1)如果主构造器无参数,小括号可省略
//class Person (){
class Person {
println("主构造器")
var name: String = _
var age: Int = _
def this(age: Int) {
this()
this.age = age
println("辅助构造器")
}
def this(age: Int, name: String) {
this(age)
this.name = name
}
}
object Person {
def main(args: Array[String]): Unit = {
val person2 = new Person(18)
}
}
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
# 构造器参数
Scala 类的主构造器函数的形参包括三种类型:未用任何修饰、var 修饰、val 修饰
- 未用任何修饰符修饰,这个参数就是一个局部变量
- var 修饰参数,作为类的成员属性使用,可以修改
- val 修饰参数,作为类只读属性使用,不能修改
class Person(name: String, var age: Int, val sex: String) {
}
object Test {
def main(args: Array[String]): Unit = {
var person = new Person("bobo", 18, "男")
// (1)未用任何修饰符修饰,这个参数就是一个局部变量
// printf(person.name)
// (2)var修饰参数,作为类的成员属性使用,可以修改
person.age = 19
println(person.age)
// (3)val修饰参数,作为类的只读属性使用,不能修改
// person.sex = "女"
println(person.sex)
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
# 继承
class 子类名 extends 父类名 { 类体 }
- 子类继承父类的属性和方法
- scala 是单继承
- 继承的调用顺序:父类构造器 -> 子类构造器
class Person(nameParam: String) {
var name = nameParam
var age: Int = _
def this(nameParam: String, ageParam: Int) {
this(nameParam)
this.age = ageParam
println("父类辅助构造器")
}
println("父类主构造器")
}
class Emp(nameParam: String, ageParam: Int) extends Person(nameParam, ageParam) {
var empNo: Int = _
def this(nameParam: String, ageParam: Int, empNoParam: Int) {
this(nameParam, ageParam)
this.empNo = empNoParam
println("子类的辅助构造器")
}
println("子类主构造器")
}
object Test {
def main(args: Array[String]): Unit = {
new Emp("z3", 11,1001)
}
}
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
# 抽象属性和抽象方法
- 定义抽象类:abstract class Person {} 通过 abstract 关键字标记抽象类
- 定义抽象属性:val|var name:String 一个属性没有初始化,就是抽象属性
- 定义抽象方法:def hello ():String 只声明而没有实现的方法,就是抽象方法
abstract class Person { //通过abstract关键字标记抽象类
val name: String //一个属性没有初始化,就是抽象属性
def hello(): Unit //只声明而没有实现的方法,就是抽象方法
}
class Teacher extends Person {
val name: String = "teacher"
def hello(): Unit = {
println("hello teacher")
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# 继承和重写
- 如果父类为抽象类,那么子类需要将抽象的属性和方法实现,否则子类也需声明为抽象类
- 重写非抽象方法需要用 override 修饰,重写抽象方法则可以不加 override。
- 子类中调用父类的方法使用 super 关键字
- 子类对抽象属性进行实现,父类抽象属性可以用 var 修饰; 子类对非抽象属性重写,父类非抽象属性只支持 val 类型,而不支持 var。 因为 var 修饰的为可变变量,子类继承之后就可以直接使用,没有必要重写
- Scala 中属性和方法都是动态绑定,而 Java 中只有方法为动态绑定,属性为静态绑定 (编译看左,运行看右)。
class Person {
val name: String = "person"
def hello(): Unit = {
println("hello person")
}
}
class Teacher extends Person {
//可以对非抽象属性重写 如果是可变变量并且有值不推荐重写
override val name: String = "teacher"
//val name: String = "teacher" //不使用override关键字同样可以重写属性
//override def hello(): Unit = {} //不使用override关键字同样可以重写方法
//如果不是抽象方法重写必须要使用override关键字
override def hello(): Unit = {
//super.hello() //可以通过super.方法名()调用原父类方法
println("hello teacher")
}
}
object Test {
def main(args: Array[String]): Unit = {
val teacher: Teacher = new Teacher()
println(teacher.name)
teacher.hello()
val teacher1:Person = new Teacher
println(teacher1.name)
teacher1.hello()
}
}
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
# 动态绑定
Scala 中属性和方法都是动态绑定,而 Java 中只有方法为动态绑定,属性为静态绑定 (编译看左,运行看右)。
Java
class Person {
public String name = "person";
public void hello() {
System.out.println("hello person");
}
}
class Teacher extends Person {
public String name = "teacher";
@Override
public void hello() {
System.out.println("hello teacher");
}
}
public class TestDynamic {
public static void main(String[] args) {
Teacher teacher = new Teacher();
Person teacher1 = new Teacher();
System.out.println(teacher.name); //teacher
teacher.hello(); //hello teacher
System.out.println(teacher1.name);// person
teacher1.hello(); // hello teacher
}
}
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
Scala
class Person {
val name: String = "person"
def hello(): Unit = {
println("hello person")
}
}
class Teacher extends Person {
override val name: String = "teacher"
override def hello(): Unit = {
println("hello teacher")
}
}
object Test {
def main(args: Array[String]): Unit = {
val teacher: Teacher = new Teacher()
println(teacher.name) // teacher
teacher.hello() // hello teacher
val teacher1:Person = new Teacher
println(teacher1.name) // teacher
teacher1.hello() // hello teacher
}
}
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