学习链接:https://www.bilibili.com/video/BV1Xh411S7bP?p=70&spm_id_from=pageDriver
1 Scala包
- 基本语法 package 包名
Scala包的三大作用(和Java一样)
- 区分相同名字的类
- 当类很多时,可以很好的管理类
- 控制访问范围
1.1 包的命名
命名规则:只能包含数字、字母、下划线、小圆点,但不能用数字开头,也不要使用关键字1.2 包说明(包语句)
Scala 有两种包的管理风格,一种方式和 J ava 的包管理风格相同,每个源文件一个包( 包
名和源文件所在路径不要求必须一致 ),包名用 “.”进行分隔以表示包的层级关系,如com .aaa.scala 。另一种风格,通过嵌套的风格表示层级关系 ```scala // 用嵌套风格定义包 package com {
import com.aaa.scala.Inner
// 在外层包中定义单例对象 object Outer { var out: String = “out”
def main(args: Array[String]): Unit = { println(Inner.in) // 外层不能直接访问内层,除非导包 } } package aaa { package scala { // 内层包中定义单例对象 object Inner {
var in: String = "in"
def main(args: Array[String]): Unit = {
println(Outer.out) // out
Outer.out = "outer"
println(Outer.out) // outer
}
} }
}
}
// 在同一文件中定义多个包 package bbb { package ccc {
import com.aaa.scala.Inner
object Test01_Package{
def main(args: Array[String]): Unit = {
println(Inner.in)
}
}
}
}
第二种风格有以下特点:
- 一个源文件中可以声明多个package
- 子包中的类可以直接访问父包中的内容,无需导包
<a name="usksm"></a>
## 1.3 包对象
在Scala中可以为每个包定义一个同名的包对象,定义在包对象中的成员,作为其对应包下所有class和object的共享变量,可以被直接访问。<br />
```scala
package object chapter06 {
// 定义当前包共享的属性和方法
val commonValue = "aaa"
def commonMethod() ={
println(s"${commonValue}")
}
}
采用嵌套方式管理包,包对象可与包定义在同一文件中,但是要保证包对象与包声明在同一作用域中 ```scala // 用嵌套风格定义包 package com {
import com.aaa.scala.Inner
// 在外层包中定义单例对象 object Outer { var out: String = “out”
def main(args: Array[String]): Unit = {
println(Inner.in) // 外层不能直接访问内层,除非导包
} } package aaa { package scala {
// 内层包中定义单例对象
object Inner {
var in: String = "in"
def main(args: Array[String]): Unit = {
println(Outer.out) // out
Outer.out = "outer"
println(Outer.out) // outer
}
}
}
}
}
// 在同一文件中定义多个包 package bbb { package ccc {
import com.aaa.scala.Inner
object Test01_Package{
def main(args: Array[String]): Unit = {
println(Inner.in)
}
}
}
}
```scala
object Test02_PackageObject {
def main(args: Array[String]): Unit = {
commonMethod()
println(commonValue)
}
}
package chapter06 {
object Test02_PackageObject {
def main(args: Array[String]): Unit = {
commonMethod()
println(commonValue)
}
}
}
package ccc{
package ddd{
object Test02_PackageObject{
def main(args: Array[String]): Unit = {
println(school)
}
}
}
// 定义一个包对象 在同一层级下
package object ddd{
val school: String = "xxschool"
}
}
导包
- 可以在顶部使用import导入,在这个文件中的所有类都可以使用
- 局部导入:什么时候使用,什么时候导入,在其作用范围内都可以使用
- 通配符导入:import java.util._
- 给类起名:import java.util.{ArrayList=>JL}
- 导入相同包的多个类:import java.util.{HashSet,ArrayList}
- 屏蔽类:import java.util.{ArrayList=>,} 导入了util中除ArrayList以外的所有
- 导入包的绝对路径:new root.java.util.HashMap
package java {
package util {
class HashMap {
}
}
}
Scala中的三个默认导入分别是:
Scala语法中,类并不声明为public,所有这些类都具有共有可见性(即默认就是public)
- 一个Scala源文件可以包含多个类 ```scala import scala.beans.BeanProperty
object Test03_Class { def main(args: Array[String]): Unit = { // 创建一个对象 val student = new Student() // student.name 私有属性,访问不到 println(student.sex) student.sex = “famale” } }
// 定义一个类 默认是public,但加上public会报错 class Student { // 定义属性 private var name: String = “aaa” @BeanProperty // 创建符合Java规范的getter setter val age: Int = 18 var sex: String = _ // 表示初值为空 }
<a name="nT340"></a>
## 2.2 属性
属性是类的一个组成部分<br />**基本语法:**<br />[修饰符] var|val 属性名称 [:类型] = 属性值<br />Bean属性(@BeanProperty),可以自动生成规范的setXxx/getXxx方法
```scala
class Student {
// 定义属性
private var name: String = "aaa"
@BeanProperty // 创建符合Java规范的getter setter
val age: Int = 18
var sex: String = _ // 表示初值为空
}
3 封装
Scala中的public属性,底层实际为private,并通过get方法(obj.field())和set方法(obj.field_=(value))对其进行操作。
Scala 并不推荐将属性设为 private ,再为其设置public 的 get 和 set 方法的做法。但由于很多Java框架都利用反射调用 getXXX和setXXX方法,有时候为了和这些框架兼容,也会为 Scala 的属性设置 getXXX 和 setXXX 方法(通过@BeanProperty 注解实现)。
3.1 访问权限
Scala中属性和方法的默认访问权限public,但Scala中无public关键字
private为私有权限,只在类的内部和伴生对象中可用
protected为受保护权限,Scala中受保护权限同类、子类可访问,同包无法访问
private[包名]增加包访问权限,包名下的其他类也可以使用
object Test04_ClassForAccess {
}
// 定义一个父类
class Person {
private var idCard: String = "123456"
protected var name: String = "aaa"
var sex: String = "female"
private[chapter06] var age: Int = 18
def printInfo() = {
println(s"Person: $idCard $name $sex $age")
}
}
object Test04_Access {
def main(args: Array[String]): Unit = {
// 创建对象
val person: Person = new Person()
// person.idCard 私有属性无法访问
// person.name protected在当前类和子类能被访问到
println(person.age)
println(person.sex)
person.printInfo()
}
}
// 定义一个子类
class Worker extends Person {
override def printInfo(): Unit = {
// println(idCard) // error ,是私有的属性,只能在类内部或伴生对象访问
name = "bob"
age = 25
sex = "male"
println(s"Worker: $name $sex $age")
}
}
3.2 构造器
Scala构造对象也需要调用构造方法,可以有任意多个构造方法
Scala类的构造器包括:主构造器和辅助构造器
基本语法:
class 类名(形参列表) { // 主构造器
// 类体
def this(形参列表) { // 辅助构造器
}
def this(形参列表) { // 辅助构造器可以有多个
}
}
- 辅助构造器,函数的名称this,可以有国歌,编译器通过参数的个数及类型来区分
- 辅助构造方法不能直接构建对象,必须直接或间接调用主构造方法
构造器调用其他另外的构造器,要求被调用构造器必须提前声明 ```scala object Test05_Constructor { def main(args: Array[String]): Unit = { val student1 = new Student1 // ()可以省略 student1.student1() /*
主构造方法被调用 不是构造方法,是一般方法 */
val student2 = new Student1(“aaa”) /*
- 主构造方法被调用
辅助构造方法一被调用 name: aaa age: 0 */
val student3 = new Student1(“bbb”, 25) /*
- 主构造方法被调用
- 辅助构造方法一被调用 name: bbb age: 0
- 辅助构造方法二被调用 name: bbb age: 25 */ } }
// 定义一个类 //class Student1 { // //} // 这样写表示主构造器没有参数,省略了空括号
class Student1() { // 定义属性 var name: String = var age: Int =
println(“1. 主构造方法被调用”)
// 声明辅助构造方法 def this(name: String) { this() // 直接调用主构造器 println(“2. 辅助构造方法一被调用”) this.name = name println(s”name: $name age: $age” ) }
def this(name: String, age: Int) { this(name) println(“3. 辅助构造方法二被调用”) this.age = age println(s”name: $name age: $age” ) }
def student1(): Unit = { println(“不是构造方法,是一般方法”) } }
<a name="YlNlq"></a>
## 3.3 构造器参数
Scala类的主构造器函数的形参包括三种类型:未用任何修饰、var修饰、val修饰
- 未用任何修饰符修饰,这个参数就是一个局部变量
- var修饰参数,作为类的成员属性使用,可以修改
- val修饰参数,作为类只读属性使用,不能修改
```scala
object Test06_ConstructorParams {
def main(args: Array[String]): Unit = {
val student2 = new Student2
println(s"student2: name = ${student2.name}, age = ${student2.age}") // student2: name = null, age = 0
student2.name = "aaa"
student2.age = 18
println(s"student2: name = ${student2.name}, age = ${student2.age}") // student2: name = aaa, age = 18
val student3 = new Student3("bbb", 20)
println(s"student3: name = ${student3.name}, age = ${student3.age}") // student3: name = bbb, age = 20
val student5 = new Student5("bbb", 20)
println(s"student5: name = ${student5.name}, age = ${student5.age}")
// student5.age = 26 常量 不能更改
val student6 = new Student6("ccc", 26, "xxxSchool")
println(s"student6: name = ${student6.name}, age = ${student6.age}")
student6.printInfo() // student6: name = ccc, age = 26, school = xxxSchool
}
}
4 继承和多态
基本语法:
class 子类名 extends 父类名 { 类体 }
- 子类继承父类的属性和方法
Scala是单继承 ```scala object Test07_Inherit { def main(args: Array[String]): Unit = { val student1 = new Student7(“aaa”, 18) /*
- 父类的主构造器调用
子类的主构造器调用 */
val student2 = new Student7(“bbb”, 20, “std001”) /*
- 父类的主构造器调用
- 子类的主构造器调用
- 子类的辅助构造器调用 */ } }
// 定义一个父类 class Person7() { var name: String = var age: Int =
println(“1. 父类的主构造器调用”)
def this(name: String, age: Int) { this() println(“2. 父类的辅助构造器调用”) this.name = name this.age = age }
def printInfo(): Unit = { println(s”Person: $name $age”) } }
// 定义子类 class Student7(name: String, age: Int) extends Person7 { var stdNo: String = _ println(“3. 子类的主构造器调用”)
def this(name: String, age: Int, stdNo: String) { this(name, age) println(“4. 子类的辅助构造器调用”) this.stdNo = stdNo }
override def printInfo(): Unit = { println(s”Student: $name $age $stdNo”) } }
**动态绑定**
```scala
object Test07_Inherit {
def main(args: Array[String]): Unit = {
val student1 = new Student7("aaa", 18)
/*
1. 父类的主构造器调用
3. 子类的主构造器调用
*/
val student2 = new Student7("bbb", 20, "std001")
/*
1. 父类的主构造器调用
3. 子类的主构造器调用
4. 子类的辅助构造器调用
*/
val teacher = new Teacher
teacher.printInfo()
/*
1. 父类的主构造器调用
Teacher
*/
def personInfo(person: Person7): Unit = {
person.printInfo()
}
println("======================")
val person = new Person7
personInfo(student1)
personInfo(teacher)
personInfo(person)
}
}
// 定义一个父类
class Person7() {
var name: String = _
var age: Int = _
println("1. 父类的主构造器调用")
def this(name: String, age: Int) {
this()
println("2. 父类的辅助构造器调用")
this.name = name
this.age = age
}
def printInfo(): Unit = {
println(s"Person: $name $age")
}
}
// 定义子类
class Student7(name: String, age: Int) extends Person7 {
var stdNo: String = _
println("3. 子类的主构造器调用")
def this(name: String, age: Int, stdNo: String) {
this(name, age)
println("4. 子类的辅助构造器调用")
this.stdNo = stdNo
}
override def printInfo(): Unit = {
println(s"Student: $name $age $stdNo")
}
}
class Teacher extends Person7 {
override def printInfo(): Unit = {
println(s"Teacher")
}
}
动态绑定:Scala中属性和方法都是动态绑定,Java中只有方法是动态绑定
object Test08_DynamicBind {
def main(args: Array[String]): Unit = {
val student: Person8 = new Student8
// Scala属性和方法都是动态绑定的
println(student.name) // student
student.hello() // hello student
}
}
class Person8 {
val name: String = "person"
def hello(): Unit = {
println("hello person")
}
}
class Student8 extends Person8 {
override val name: String = "student"
override def hello(): Unit = {
println("hello student")
}
}
对比Java的动态绑定,属性静态绑定,方法动态绑定
public class TestDynamicBind {
public static void main(String[] args) {
Worker worker = new Worker();
System.out.println(worker.name);
worker.hello();
worker.hi();
// 多态
Person person = new Worker();
System.out.println(person.name); // 静态绑定属性 person
person.hello(); // 动态绑定方法 hello worker
// person.hi();
}
}
class Person {
String name = "person";
public void hello() {
System.out.println("hello person");
}
}
class Worker extends Person {
String name = "worker";
public void hello() {
System.out.println("hello worker");
}
public void hi() {
}
}
5 抽象类
5.1 抽象属性和抽象方法
5.1.1 基本语法:
- 定义抽象类:abstract class Person{} //通过abstract关键字标记抽象类
- 定义抽象属性:val|var name: String // 一个属性没有初始化,就是抽象属性
- 定义抽象方法: def hello(): String // 只声明而没有实现的方法,就是抽象方法
类中只要存在抽象属性和抽象方法,就要定义成抽象类
5.1.2 继承&重写
- 如果父类为抽象类,子类需要将抽象的属性和方法实现,否则子类也需声明为抽象类
- 重写非抽象方法需要override修饰,重写抽象方法可以不加override
- 子类中调用父类的方法使用super关键字
- 子类对抽象属性进行实现,父类抽象属性可以用var修饰
子类对非抽象属性重写,父类非抽象属性只支持val类型,而不支持var
(var修饰的为可变变量,子类继承之后就可以直接使用,没有必要重写)
object Test09_AbstractClass {
def main(args: Array[String]): Unit = {
val student = new Student9
student.eat()
student.sleep()
}
}
// 定义抽象类
abstract class Person9 {
// 非抽象属性
val name: String = "person"
// 抽象属性
var age: Int
// 非抽象方法
def eat(): Unit = {
println("person eat")
}
// 抽象方法
def sleep(): Unit
}
// 定义具体的实现子类
class Student9 extends Person9 {
// 实现抽象属性和方法
var age: Int = 18
override def sleep(): Unit = { // override可以省略
println("student sleep")
} // override可以省略
// 重写非抽象属性和方法
override val name: String = "student"
override def eat(): Unit = {
super.eat()
println("student eat")
}
}
5.2 匿名子类
可以通过包含带有定义或重写的代码块的方式创建一个匿名的子类
object Test10_AnnoymousClass {
def main(args: Array[String]): Unit = {
val person: Person10 = new Person10 {
override var name: String = "aaa"
override def eat(): Unit = println("person eat")
}
println(person.name)
person.eat()
}
}
// 定义抽象类
abstract class Person10 {
var name: String
def eat(): Unit
}
6 单例对象(伴生对象)
Scala没有静态的操作。为了和Java交互,用单例对象模拟类对象。若单例对象名与类名一致,称该单例对象是这个类的伴生对象,这个类的所有静态内容都可以放在它的伴生对象中声明。
6.1 单例对象语法
基本语法:
object Person {
val school: String = "xxx"
}
- 单例对象采用object关键字声明
- 单例对象对应得类称为伴生类,伴生对象的名称应该和伴生类名一致
- 单例对象中的属性和方法都可以通过伴生对象名(类名)直接调用访问 ```scala object Test11_Object { def main(args: Array[String]): Unit = { val student = new Student11(“aaa”, 8) // student: name = aaa , age = 8, school = xxxschool student.printInfo() } }
// 定义类 class Student11(val name: String, val age: Int) { def printInfo(): Unit = { println(s”student: name = $name , age = $age, school = ${Student11.school}”) // 这里的Student11不是类,是伴生对象 } }
// 伴生对象 object Student11 { val school: String = “xxxschool” }
**构造方法私有化**
```scala
object Test11_Object {
def main(args: Array[String]): Unit = {
// val student = new Student11("aaa", 8) // student: name = aaa , age = 8, school = xxxschool
// student.printInfo()
val student = Student11.newStudent("aaa", 18)
student.printInfo()
}
}
// 定义类
// 构造方式私有化
class Student11 private (val name: String, val age: Int) {
def printInfo(): Unit = {
println(s"student: name = $name , age = $age, school = ${Student11.school}") // 这里的Student11不是类,是伴生对象
}
}
// 伴生对象
object Student11 {
val school: String = "xxxschool"
// 定义一个类的对象实例的创建方法
def newStudent(name: String, age: Int): Student11 = new Student11(name, age)
}
6.2 apply方法
- 通过伴生对象的apply方法,实现不使用new方法创建对象
- 如果想让主构造器变成私有的,可以在()之前加上private
- apply方法可以重载
- Scala中 obj (arg 的语句实际是在调用该对象的 apply 方法,即 obj .apply(arg)。用
以统一面向对象编程和函数式编程的风格。
当使用new关键字构建对象时,调用的其实是类的构造方法,当直接使用类名构建对象时,调用的是伴生对象的apply方法 ```scala object Test11_Object { def main(args: Array[String]): Unit = { // val student = new Student11(“aaa”, 8) // student: name = aaa , age = 8, school = xxxschool // student.printInfo() val student = Student11.newStudent(“aaa”, 18) student.printInfo()
val student1 = Student11.apply(“bbb”, 20) student1.printInfo()
// 与上面的student1写法等效 val student2 = Student11(“bbb”, 21) student2.printInfo() } }
// 定义类 // 构造方式私有化 class Student11 private (val name: String, val age: Int) { def printInfo(): Unit = { println(s”student: name = $name , age = $age, school = ${Student11.school}”) // 这里的Student11不是类,是伴生对象 } }
// 伴生对象 object Student11 { val school: String = “xxxschool”
// 定义一个类的对象实例的创建方法 def newStudent(name: String, age: Int): Student11 = new Student11(name, age)
def apply(name: String, age: Int): Student11 = new Student11(name, age) }
**单例模式**
```scala
object Test12_Singleton {
def main(args: Array[String]): Unit = {
val student1 = Student12.getInstance()
student1.printInfo()
val student2 = Student12.getInstance()
student1.printInfo()
println(student1)
println(student2)
}
}
// 定义类
class Student12 private (val name: String, val age: Int) {
def printInfo(): Unit = {
println(s"student: name = $name , age = $age, school = ${Student11.school}") // 这里的Student11不是类,是伴生对象
}
}
// 饿汉式单例设计模式
//object Student12 {
// private val student: Student12 = new Student12("ccc", 22)
// def getInstance(): Student12 = student
//}
// 懒汉式单例设计模式
object Student12 {
private var student: Student12 = _
def getInstance(): Student12 = {
if (student == null) {
// 如果没有对象实例的话,创建一个
student = new Student12("ddd", 25)
}
student
}
}
7 特质(Trait)
Scala语言中,采用特质trait来代替接口的概念,多个类具有相同的特质(特征)时,可以将这个特质(特征)独立出来,采用关键字trait声明。
Scala中的trait中既可以有抽象属性和方法,也可以有具体的属性和方法,一个类可以混入多个特质。
Scala引入trait特征,可以代替接口,也是对单继承机制的一种补充。
7.1 特质声明
基本语法
trait 特质名 {
trait 主体
}
7.2 特质基本语法
一个类具有某种特质(特征),意味着这个类满足了这个特质(特征)的所有要素,在使用时,采用extends关键字,如果有多个特质或存在父类,需要采用with关键字连接。
基本语法:
没有父类:class 类名 extends 特质1 with 特质2 with 特质3…
有父类:class 类名 extends 父类 with 特质1 with 特质2…
- 类和特质的关系:使用继承的关系
- 当一个类去继承特质时,第一个连接词时extends,后面是with
- 如果一个类在同时继承特质和父类时,把父类写在extends后 ```scala object Test13_Trait { def main(args: Array[String]): Unit = { val student = new Student13 student.sayHello() student.study() student.watch() student.play() } }
// 定义一个父类 class Person13 { val name: String = “person” var age: Int = 18
def sayHello(): Unit = { println(“hello from: “ + name) } }
// 定义一个特质 trait Young { // 声明抽象和非抽象属性 var age: Int val name: String = “young”
// 声明抽象和非抽象的方法 def play(): Unit = { println(“young people is playing”) }
def watch(): Unit }
class Student13 extends Person13 with Young { // 重写冲突的属性 override val name: String = “student” // 实现抽象方法 override def watch(): Unit = println(s”student ${name} is watching”)
def study(): Unit = println(s”student ${name} is studying”)
// 重写父类方法 override def sayHello(): Unit = { super.sayHello() println(s”hello from student $name”) } }
<br />**特质混入**<br />一个类可以混入(mixin)多个特质<br />所有的Java接口都可以当作Scala的特质使用<br />动态混入-灵活扩展类的功能
- 创建对象时混入trait,而不是类混入该trait
- 如果混入的trait中有未实现的方法,需要实现
```scala
object Test14_TraitMixin {
def main(args: Array[String]): Unit = {
val student = new Student14
student.study()
student.increase()
student.play()
student.increase()
student.watch()
student.increase()
}
}
// 定义一个特质
trait Knowledge {
var amount: Int = 0
def increase(): Unit // 抽象方法
}
class Student14 extends Person13 with Young with Knowledge {
// 重写冲突的属性
override val name: String = "student"
// 实现抽象方法
override def watch(): Unit = println(s"student ${name} is watching")
def study(): Unit = println(s"student ${name} is studying")
// 重写父类方法
override def sayHello(): Unit = {
super.sayHello()
println(s"hello from student $name")
}
// 实现特质中的抽象方法
override def increase(): Unit = {
amount += 1
println(s"student $name knowledge increased: $amount")
}
}
object Test14_TraitMixin {
def main(args: Array[String]): Unit = {
val student = new Student14
student.study()
student.increase()
student.play()
student.increase()
student.watch()
student.increase()
println("=============")
// 动态混入
val studentWithTalent = new Student14 with Talent {
override def dancing(): Unit = println("student is good at dancing")
override def singing(): Unit = println("student is good at singing")
}
studentWithTalent.sayHello()
studentWithTalent.play()
studentWithTalent.study()
studentWithTalent.dancing()
studentWithTalent.singing()
}
}
// 定义一个特质
trait Knowledge {
var amount: Int = 0
def increase(): Unit // 抽象方法
}
trait Talent {
def singing(): Unit
def dancing(): Unit
}
class Student14 extends Person13 with Young with Knowledge {
// 重写冲突的属性
override val name: String = "student"
// 实现抽象方法
override def watch(): Unit = println(s"student ${name} is watching")
def study(): Unit = println(s"student ${name} is studying")
// 重写父类方法
override def sayHello(): Unit = {
super.sayHello()
println(s"hello from student $name")
}
// 实现特质中的抽象方法
override def increase(): Unit = {
amount += 1
println(s"student $name knowledge increased: $amount")
}
}
7.3 特质叠加
若混入的特质中具有相同的方法,出现继承冲突:
- 一个类混入两个trait(TraitA,TraitB)中具有相同的具体方法,且两个trait之间没有任何关系
解决冲突:在类中重写冲突方法
object Test15_TraitOverlying {
def main(args: Array[String]): Unit = {
val student = new Student15
student.increase()
}
}
trait Knowledge15 {
var amount: Int = 0
def increase(): Unit = {
println("knowledge increased")
}
}
trait Talent15 {
def singing(): Unit
def dancing(): Unit
def increase(): Unit = {
println("talent increased")
}
}
class Student15 extends Person13 with Talent15 with Knowledge15 {
override def dancing(): Unit = println("dancing")
override def singing(): Unit = println("singing")
override def increase(): Unit = {
super.increase()
}
}
调用最后一个trait的increase()
- 一个类混入的两个trait(TraitA,TraitB)中具有相同的具体方法,且两个trait继承自相同的trait(TratiC),即钻石问题
解决冲突:特质叠加
object Test_Trait {
def main(args: Array[String]): Unit = {
// 钻石问题特征叠加
val myFootBall = new MyFootBall
println(myFootBall.describe())
}
}
// 定义球类特征
trait Ball {
def describe(): String = "ball"
}
// 定义颜色特征
trait ColorBall extends Ball {
var color: String = "red"
override def describe(): String = color + super.describe()
}
// 定义种类特征
trait CategoryBall extends Ball {
var category: String = "foot"
override def describe(): String = category + super.describe()
}
// 定义一个自定义球的类
class MyFootBall extends CategoryBall with ColorBall {
override def describe(): String = "my ball is a " + super.describe()
}
指定调哪个父类
// 定义一个自定义球的类
class MyFootBall extends CategoryBall with ColorBall {
override def describe(): String = "my ball is a " + super[CategoryBall].describe()
}
7.4 特质叠加执行顺序
当一个类混入多个特质的时候,Scala会对所有的特质及其父特质按照一定的顺序进行排序
类的定义:class MyBall extends Category with Color
叠加顺序:MyBall ->Color -> Category -> Ball
- 列出混入的第一个特质的继承关系,作为临时叠加顺序
Category -> Ball
- 列出混入的第二个特质的继承关系,并将该顺序叠加到临时顺序前边
Color -> Ball
- 将子类放在临时叠加顺序的第一个,得到最终叠加顺序
7.5 特质和抽象类的区别
- 优先使用特质。一个类可以扩展多个特质,但却只能扩展一个抽象类
- 如果需要构造函数参数,使用抽象类。抽象类可以定义带参数的构造函数,特质不行
7.6 特质自身类型
自身类型可实现依赖注入的功能 ```scala object Test16_TraitSelfType { def main(args: Array[String]): Unit = { val user = new RegisterUser(“aaa”, “123456”) user.insert() } }
// 用户类 class User(val name: String, val password: String)
trait UserDao { _: User =>
def insert(): Unit = { println(s”insert into db: ${this.name}”) } }
// 定义注册用户类 class RegisterUser(name: String, password: String) extends User(name, password) with UserDao

<a name="xe2IO"></a>
# 8 扩展
<a name="ZOZOc"></a>
## 8.1 类型检查和转换
1. obj.isInstanceOf[T]:判断obj是不是T类型
1. obj.asInstanceOf[T]:将obj强转成T类型
1. classOf获取对象的类名
```scala
object Test17_Extends {
def main(args: Array[String]): Unit = {
// 1. 类型的检测和转换
val student: Student17 = new Student17("aaa", 18)
student.study()
student.sayHi()
val person: Person17 = new Student17("bbb", 20)
person.sayHi()
println("student is Student17: " + student.isInstanceOf[Student17]) // true
println("student is Person17: " + student.isInstanceOf[Person17]) // true
println("person is Person17: " + person.isInstanceOf[Person17]) // true
println("person is Student17: " + person.isInstanceOf[Student17]) // true
// 类型转换
if (person.isInstanceOf[Student17]) {
val newStudent = person.asInstanceOf[Student17]
newStudent.study() // student study
}
println(classOf[Student17]) // class chapter06.Student17
}
}
class Person17(name: String, age: Int) {
def sayHi(): Unit = {
println("hi from person " + name)
}
}
class Student17(name: String, age: Int) extends Person17(name, age) {
override def sayHi(): Unit = {
println("hi from student " + name)
}
def study(): Unit = {
println("student study")
}
}
8.2 枚举类和应用类
枚举类:需要继承Enumeration
应用类:需要继承App
object Test17_Extends {
def main(args: Array[String]): Unit = {
println(WorkDay.MONDAY) // Monday
}
}
// 定义枚举类对象
object WorkDay extends Enumeration {
val MONDAY = Value(1, "Monday")
val TUESDAY = Value(2, "Tuesday")
}
// 定义应用类对象
object TestApp extends App {
println("app start")
}
8.3 Type定义新类型
使用 type 关键字可以定义新的数据数据类型名称,本质上就是类型的一个别名
object Test {
def main(args: Array[String]): Unit = {
type S=String
var v:S="abc"
def test():S="xyz"
}
}