I. 类

  • 类的定义
  • 类成员的可见性
  • 方法的定义方式
  • 构造器

1. 类的定义

  1. class Classname{
  2. var v = 0
  3. val vl = 1
  4. def func(args): return_type = {content} // 无返回Unit
  5. }
  6. class Counter{
  7. var value = 0
  8. def increment(step: Int): Unit = {value += step}
  9. def current(): Int = {value}
  10. }
  11. // 实例化
  12. val myCounter = new Counter
  13. myCounter.value = 5
  14. myCounter.increment(3)
  15. println(myCounter.current) // 调用无参数方法时,可以省略方法后的括号

2. 类的可见性

当没有修饰词时,成员默认为public
私有成员:

  • private -> 本类型和嵌套类型可见
  • protected -> 本类型和其他继承类型可见

建议编程中不要直接定义(暴露)public字段,而是通过getter/setter函数去操作某些私有变量。
下面两个方法成对出现:

  • value = 类似getter方法
  • value_= 一个方法名称,类似setter方法
  1. class Counter{
  2. private var privateValue = 0
  3. def value = privateValue
  4. def value_ = (newValue: Int){
  5. if(newValue > 0) privateValue = newValue
  6. }
  7. ...
  8. }
  9. val myCounter = new Counter
  10. myCounter.value_=(3) // 可简化为 myCounter.value = 3
  11. println(myCounter.value) // out: 3 其中.value是一个方法

3. 方法的定义方式

def func(args:arg_type): return_type = {...}

  • 参数不可使用val/var修饰的
  • 没有参数时,可以省略括号;同时后面定义时必须省略
  • 可以使用中缀操作符调用方法
    a.+(b) -> a+b
  • 方法体中只有一条语句时,可省略大括号
  • 当无返回值时,可以省略:Unit=
    1. class Counter{
    2. var value = 0
    3. // def increment(step:Int):Unit = {value += step}
    4. def increment(step:Int){value += step}
    5. def current() = value // value的类型可以自动推断出来,所以不需要声明
    6. }

4. 构造器

类名称(参数列表)

  • 类本身作为主构造器 this
  • 可以加val/var修饰。同时自动成为类内成员,自动创造读写方法
  • 如果没有val/var修饰,作用又是为了传递参数
    1. class Counter(var name: String)
    2. var mycounter = new Counter("Runner")
    3. mycounter.name_=("Timer")
    4. println(mycounter.name) // out: Timer

辅助构造器
一个类:主构造器 + 多个辅助构造器 this 表示当前类对象

  • 每个辅助构造器必须调用前一个构造器 ```scala class Counter{ private var value = 0 private var name = “” private var step = 1 println(“the main constructor”) def this(name: String){
    1. this() // 调用主构造器
    this.name = name printf(f”the 2nd constructor: $name\n”) } def this(name: String, step: Int){
    1. this(name) // 调用前一个辅助构造器
    this.step = step printf(f”the 3rd constructor: $name\n”) } def increment(step: Int): Unit = {value += step} def current(): Int = {value} }

val c1 = new Counter // 主构造器 val c2 = new Counter(“the second Counter”) // 第二个构造器 val c3 = new Counter(“the third Counter”, 3)

  1. ---
  2. <a name="JPkhF"></a>
  3. # II. 对象
  4. - 单例对象
  5. - update方法
  6. - apply方法
  7. - unapply方法
  8. <a name="5PSbr"></a>
  9. ## 1. 单例对象
  10. - 静态的方法调用,会记住之前的状态,不会重置
  11. - 不需要实例化,可以直接调用静态方法
  12. ```scala
  13. object Person{
  14. private var lastId = 0
  15. def newPersonId() = {
  16. lastId += 1
  17. lastId // 方法返回值
  18. }
  19. }
  20. printf(f"The first person id: $Person.newPersonId()")

单例对象分两类

  • 伴生对象
    • 一个文件中同时出现 class A{}; object A{}
    • 互为伴生对象,可以互相访问类内部的变量和方法
  • 孤立对象

2. apply**

为什么声明一个数组对象时,不需要new?

  • 因为scala会自动帮你调用Array这个类的伴生对象中apply方法,创建一个数组对象
    1. val myStrArr = Array("BigData", "Hadoop", "Spark")

apply调用约定

  • 作为一种工厂方法,用于生成类
  • 括号传递给类实例/单例对象名称参数时自动调用apply
  • scala会在相应的类中查找方法名为apply
  • apply参数列表需要与传入的参数一致
  • 调用apply方法
    1. class TestApplyClass{
    2. def apply(param: String){
    3. println("apply method called: " + param)
    4. }
    5. }

我们可以将类的构造方法以apply方法的形式,写入伴生对象中。在实例化时,自动调用apply方法,自动生成类。

  1. class Car(name: String){
  2. def info(){
  3. println("Car name is " + name)
  4. }
  5. }
  6. object Car{
  7. def apply(name: String) = new Car(name)
  8. }
  9. // 孤立对象: 定义程序的入口函数
  10. object MyTestApply{
  11. def main(args: Array[String]){
  12. val mycar = Car("BMW") // 调用伴生对象中的apply方法
  13. mycar.info() // out: Car name is BMW
  14. }
  15. }

JAVA使用类过程

  1. 定义一个类
  2. new class
  3. new 一个类,生成一个实例

Scala为了融合面向对象和函数式编程

  • 面向对象:对象.方法
  • 函数式:函数名称(参数)
    1. def add = (x: Int, y: Int) => x+y //匿名函数
    2. add(4, 5) // 函数调用
    3. add.apply(4, 5) // 对象调用

3. update

  • 当对带有括号并包括一到若干参数的对象进行赋值
  • 编译器将调用update方法
  • 并将括号里的参数和等号右边的值
  • 一起作为update方法的输入参数来执行调用
    1. val myStrArr = new Array[String](3)
    2. myStrArr(0) = "BigData" //调用伴生类Array中update方法执行myStrArr.update(0, "BigData")

4. unapply

给定对象后,提取对象中的变量,解构过程

  1. object Car{
  2. def unapply(c: Car): Option[(String, Int)] = {
  3. Some((c.brand, c.price))
  4. }
  5. }
  6. object TestUnapply{
  7. def main(args: Array[String]){
  8. // 等号右侧apply构造,左侧unapply解构
  9. var Car(carbrand, carprice) = Car("BMW", 800000)
  10. println("brand: " + carbrand + "and carprice" + carprice)
  11. }
  12. }

III. 继承

  • 抽象类
  • option类
  • 扩展类
  • Scala的类层次结构

1. 抽象类

一个类中包含没有被实现的成员变量/成员函数,称为抽象类,必须用 abstract 修饰

  • 抽象字段必须给定变量类型
    1. abstract class Car(val name: String){
    2. val carBrand: String // 字段没有初始值,是抽象字段
    3. def info() // 抽象方法
    4. def greeting(){
    5. println("Welcome to my car!")
    6. }
    7. }

2. 扩展类 (子类)

extends 关键字表示继承关系;override 覆盖成员

  • 父类中已实现的方法,子类覆盖时必须添加 override
  • 父类中的抽象方法,子类实现时可不加 override
  • 只能重载val字段,不可重载var类型字段 ```scala class BMWCar extends Car{ override val carBrand = “BMW” def info(){ println(“Expensive!”) } override def greeting(){println(“BWM car!”)} }

Object MyCar{ def main(args: Array[string]) val myCar1 = new BMWCar() myCar1.greeting() myCar1.info() }

  1. <a name="ijevc"></a>
  2. ## 3. 层次结构
  3. ![](https://cdn.nlark.com/yuque/0/2020/png/2799856/1606138930828-fb177d3d-69c0-4bb4-ae9d-99e63a7fcd09.png)
  4. - AnyVal 是值类型,存入寄存器,之后进行运算
  5. - AnyRef 引用类型,new实例化对象后存入堆中,指针指向堆地址 null为子类
  6. <a name="Plul8"></a>
  7. ## 4. option类
  8. **实际编程中尽量避免使用Null,改用Option类**
  9. - Option类将返回值封装为Some对象,返回
  10. - 如果没有返回值,返回Null
  11. - 当无法确定返回值,最好将返回值类型设定为Option
  12. ```scala
  13. case class Book(val name: String, val price: Double)
  14. val books = Map(
  15. "hadoop" -> Book("Hadoop", 35.5)
  16. "spark" -> Book("Spark", 55.5)
  17. )
  18. $ books.get("hadoop")
  19. res0: Option[Book] = Some(Book(Haddop, 35.5))
  20. $ books.get("Hive")
  21. res1: Option[Book] = None
  22. $ books.get("hadoop").get
  23. res2: Book = Book(Hadoop, 35.5)
  24. $ boos.get("hive").getOrElse(Book("Unknown name", 0))
  25. Book = Book(Unknown name, 0.0)

IV. 特质 trait

Scala 中特有的概念,类似Java中的接口

  • 定义抽象方法/方法的具体方法 trait
  • 可继承,混入多个特质 -> 实现多重继承 with/extends ```scala trait Flyable{ var maxFlyHeight: Int //抽象字段 def fly()
    def breathe(){
    1. println("I can breathe.")
    } }

class Bird(flyHeight: Int) extends Flyable{ var maxFlyHeight: Int = flyHeight def fly(){ printf(“fly %d”, maxFlyHeight) } }

val b = new Bird(100) b.fly() // fly 100 b.breathe // I can breathe

trait HasLegs{…} class Animal(val category: String){…}

class Bird(flyHeight: Int) extends Animal(“Bird”) with Flyable with HasLegs{ var maxFlyHeight: Int = flyHeight val legs = 2 def fly(){println(‘fly: ‘ + maxFlyHeight)} }

  1. ---
  2. <a name="Ic6A7"></a>
  3. # V. 模式匹配
  4. <a name="Nvs26"></a>
  5. ## 1. **match-case**
  6. - 可以添加守卫 guard
  7. ```scala
  8. import scala.io.StdIn._
  9. println("Please input the score: ")
  10. val grade = readChar()
  11. grade match{
  12. case "A" => println("85-100")
  13. case "B" => println("70-84")
  14. case_ => println("error input!")
  15. }
  16. for(elem <- List(1, 2.2, "Spark")){
  17. val str = elem match{
  18. case i: Int => "int"
  19. case d: Double => "double"
  20. case s: String => "string"
  21. case_ => "unexpected value"
  22. }
  23. println(str)
  24. }
  25. // guard 在每次操作时加入条件判断
  26. for(elem <- List(1,2,3,4)){
  27. elem match{
  28. case_ if(elem%2==0) => println(elem+"is even.")
  29. case_ => println(elem + "is odd.")
  30. }
  31. }

2. case类

  • 自动重载许多实用方法 toString/equals/hashcode
  • 自动生成一个伴生对象 apply工厂方法自动生成实例,不需要new;还有unapply方法 ```scala case class Car(brand: String, price: Int)

// 上一句case类自动生成下面伴生对象 object Car{ def apply(brand: String, price: Int) = new Car(brand, price) def unapply(c: Car): Option[(String, Int)] = Some((c.brand, c.price)) }

// 用于模式匹配 case class Car(brand: String, price: Int) val myBYD = Car(“BYD”, 89000) val myBMW = Car(“BMW”, 1200000) for(car <- List(myBYD, myBMW)){ car match{ case Car(“BYD”, 89000) => println(“BYD”) //apply case Car(brand, price) => println(“Brand: “ + brand) //unapply } }

  1. ---
  2. <a name="yrrT5"></a>
  3. # VI. 包
  4. 解决程序中的命名冲突
  5. - 通配符:下划线`_`
  6. - scala隐式添加 `java.lang._` `scala._` `Predef._`
  7. ```scala
  8. # 嵌套定义
  9. package xmu{
  10. package autodepartment{
  11. class ControlCourse{
  12. ...
  13. }
  14. }
  15. package csdepartment{
  16. class OSCourse{
  17. val cc = new autodepartment.ControlCourse
  18. }
  19. }
  20. }
  21. # 导入使用
  22. import xmu.autodepartment.ControlCourse
  23. class MyClass{
  24. var myos = new ControlCourse
  25. }