面向对象编程

类的定义

class Counter{
	定义类的字段和方法
}

定义字段:使用关键字val或者var
定义方法:def 方法名(参数列表):返回结果类型={方法体}

  def increment(step: Int): Unit = {
    value += step
  }

  def current(): Int = {
    value
  }

联系起来就是

  var value = 0

  def increment(step: Int): Unit = {
    value += step
  }

  def current(): Int = {
    value
  }

类的使用:使用关键字new创建一个类的实例

    val myCounter = new Counter
    myCounter.value = 5//字段赋值
    myCounter.increment(3)//调用方法
    println(myCounter.current)//调用无参方法时,可以将省略括号

scala类的所有成员默认是公开的,即如何作用域都能直接访问到,为了数据的安全性,我们一般要设置他的可见性,在scala中类的可见性分为以下几种:

  • 默认的:如何作用域都可以访问
  • private:只对本类型和嵌套类型可见
  • protected:本类型和其继承类型均可见

为了数据的安全性,我们需要和Java一样,将字段设置为private,然后定义两个方法来对数据进行读取和修改

原本的Counter改成

package ObjectClass

class Counter {
  private var privateValue = 0
  var value = privateValue

  def getPrivateValue(): Int = {
    privateValue
  }

  def setPrivateValue(privateValue: Int): Unit = {
    if (privateValue > 0) this.privateValue = privateValue
  }

  def increment(step: Int): Unit = {
    value += step
  }

  def current(): Int = {
    value
  }
}

调用需要改成

    val myCounter = new Counter
    myCounter.setPrivateValue(5)
    myCounter.increment(3)//调用方法
    println(myCounter.current)//调用无参方法时,可以将省略括号

定义方法:def 方法名(参数列表):返回结果类型={方法体}

【Scala】面向对象编程_开发语言

构造器
Scala类的定义主体就是类的构造器,称为主构造器。在类名之后用圆括号列出主构造器的参数列表=

主构造器的参数可以使用var和·val关键字,scala内部将自动为这些参数创建私有字段,并且提供对应的访问方法
如果不需要类的参数成为类的字段,则不加关键字varval即可
定义一个带参数的构造器

class Counter02(var name:String)

使用构造器,并且对其参数来进行处理

    var myCounter02 = new Counter02("张三")
    //调用读方法
    println(myCounter02.name)
    //调用写方法
    myCounter02.name = "李四"
    println(myCounter02.name)

【Scala】面向对象编程_redis_02
Scala类可以包含零个或多个辅助构造器。辅助构造器可以使用this来进行定义,返回类型是Unit

每一个辅助构造器的第一个表达式必须是调用一个此前已经定义的辅助构造器或者主构造器,调用的形式:this(参数列表)

class Counter03 {
  private var value = 0
  private var name = ""
  private var step = 1 //计算器的默认递进步长
  println("the main constructor")

  def this(name: String) { //第一个辅助构造器
    this() //调用主构造器
    this.name = name
    printf("the first auxiliary constructor,name:%s\n", name)
  }

  def this(name: String, step: Int) { //第二个辅助构造器
    this(name) //调用前一个辅助构造器
    this.step = step
    printf("the second auxiliary constructor,name:%s,step:%d\n", name, step)
  }

  def increment(step: Int): Unit = {
    value += step
  }

  def current(): Int = {
    value
  }
}

调用

    println(new Counter03)
    println(new Counter03("Jack"))
    println(new Counter03("Jack",20))

【Scala】面向对象编程_java_03
跳转顶部


对象

Scala采用单例对象来实现Java静态成员同样的功能
使用Object关键字定义单例对象

object Person {
  private var lastId = 0

  def newPersonId() = {
    lastId += 1
    lastId
  }
}

使用示范

    println(Person.newPersonId())
    println(Person.newPersonId())
    println(Person.newPersonId())

【Scala】面向对象编程_开发语言_04
【Scala】面向对象编程_java_05
伴生对象的使用

class Person(val name: String) {
  private val id = Person.newPersonId() //调用了伴生对象中的方法

  def info() {
    printf("The id of %s is %d.\n", name, id)
  }
}

object Person {
  private var lastId = 0 //一个人的身份编号

  def newPersonId() = {
    lastId += 1
    lastId
  }

  def main(args: Array[String]) {
    val person1 = new Person("Lilei")
    val person2 = new Person("Hanmei")
    person1.info()
    person2.info()
  }
}

Apply方法
思考下行代码的执行过程

val myStr = Array("BigData","Spark")

【Scala】面向对象编程_java_06
实验使用

object ApplyTest {
  def main(args: Array[String]): Unit = {
    val myApplyTest = new ApplyTest
    myApplyTest("xxx")
    myApplyTest.apply("aaa")
  }
}

class ApplyTest {
  def apply(Parm: String): Unit = {
    println("apply method called:" + Parm)
  }
}

【Scala】面向对象编程_redis_07


伴生对象中的apply方法:将所有类的构造方法以apply方法的形式定义在伴生对象中,这样伴生对象就像生成类实例的工厂,而这些apply方法也被称为工厂方法

class Car(name: String) {
  def info(): Unit = {
    println("Car name is " + name)
  }
}

object Car {
  def apply(name: String) = new Car(name)
}

object CarTest {
  def main(args: Array[String]): Unit = {
    val myCar = Car("BYD")
    myCar.info
  }
}

【Scala】面向对象编程_spark_08
为什么要设计apply方法

  • 保持对象和函数之间使用的一致性
  • 面向对象:‘对象.方法’ VS 数学:'函数(参数)'
  • Scala中一切都是对象,包括函数也是对象

update方法

    //声明有一个长度为3的字符串数组,每个数组元素初始化为null
    val myStr = new Array[String](3)
    myStr(0) = "BigData"//实际上时执行了Array.update(0,"BigDate")
    myStr(1) = "Hadoop"

unapply

  • unapply方法用于对对象进行解构操作,与apply方法类似,该方法也会被自动调用
  • 可以认为unapply方法是apply方法的反向操作,apply方法接受构造参数变成对象,而unapply方法接受一个对象,从中提取值
object upApply {
  def main (args: Array[String]) {
    val Car02(carbrand,carprice) = Car02("BMW",800000)
    println("brand: "+carbrand+" and carprice: "+carprice)
  }

}
class Car02(val brand:String,val price:Int) {
  def info() {
    println("Car brand is "+ brand+" and price is "+price)
  }
}
object Car02{
  def apply(brand:String,price:Int)= {
    println("Debug:calling apply ... ")
    new Car02(brand,price)
  }
  def unapply(c:Car02):Option[(String,Int)]={
    println("Debug:calling unapply ... ")
    Some((c.brand,c.price))
  }
}

跳转顶部


继承

类的层次结构
【Scala】面向对象编程_java_09
【Scala】面向对象编程_java_10

抽象类

  • 如果一个类中含有为实现的成员,则必须使用abstract关键字进行修饰,定义为抽象类
abstract class abstractTest {
  val carBrand: String//字段没有初始化,就是一个抽象字段

  def info()//抽象方法

  def greeting(): Unit = {
    println("hello")
  }
}

【Scala】面向对象编程_spark_11
扩展类
Scala中只支持单一继承,不支持多重继承。使用关键字extends表示继承关系
【Scala】面向对象编程_redis_12

object extendsTest {
  def main(args: Array[String]): Unit = {
    val man = new Man()
    val woman = new Woman()
    man.info()
    man.info2()

    woman.info()
    woman.info2()
  }
}

abstract class human {
  val sex: String

  def info()

  def info2() {
    println("你好,人类")
  }
}

class Man extends human {
  override val sex: String = "男"

  override def info(): Unit = {
    printf("这是一个%s人\n", sex)
  }

  override def info2(): Unit = {
    println("你好,男人")
  }
}
class Woman extends human {
  override val sex: String = "女"

  override def info(): Unit = {
    printf("这是一个%s人\n", sex)
  }

  override def info2(): Unit = {
    println("你好,女人")
  }
}

【Scala】面向对象编程_spark_13


option
【Scala】面向对象编程_开发语言_14
跳转顶部


特质

【Scala】面向对象编程_开发语言_15
使用关键字trait定义特质

  trait Flyable {
    var maxFlyHeight: Int //抽象字段

    def fly() //抽象方法

    def breathe() { //具体的方法
      println("I can breathe")

    }
  }

【Scala】面向对象编程_开发语言_16
使用关键字extends或者·with将特质混入类中,如果特质中含有抽象成员,则必须实现,否则只能被定义为抽象类

class Bird(flyHeight:Int)extends Flyable{
  override var maxFlyHeight: Int = flyHeight

  override def fly(): Unit = {
    println("i can fly at the height of %d",maxFlyHeight)
  }
}

使用

    val bird = new Bird(100)
    bird.fly()

【Scala】面向对象编程_redis_17
将多个特质到类中

trait Flyable {
  var maxFlyHeight:Int  //抽象字段
  def fly() //抽象方法
  def breathe(){ //具体的方法
    println("I can breathe")
  }
}
trait HasLegs {
  val legs:Int   //抽象字段
  def move(){printf("I can walk with %d legs",legs)}
}
class Animal(val category:String){
  def info(){println("This is a "+category)}
}
class Bird(flyHeight:Int) extends Animal("Bird") with Flyable with HasLegs{
  var maxFlyHeight:Int = flyHeight //重载特质的抽象字段
  val legs=2 //重载特质的抽象字段
  def fly(){
    printf("I can fly at the height of %d",maxFlyHeight)
  }//重载特质的抽象方法
}

类的使用

    val  b = new Bird(108)
    b.info()
    b.fly()
    b.move()

【Scala】面向对象编程_spark_18

跳转顶部


模式匹配

最常见的模式匹配是match语句,match语句用在当需要从多个分支中进行选择的场景

    println("Please input the score:")
    val grade=readChar()
    grade match{
      case 'A' => println("85-100")
      case 'B' => println("70-84")
      case 'C' => println("60-69")
      case 'D' => println("<60")
      case _ => println("error input!")
    }
  • 通配符_相当于Java中的default分支
  • match结构中不需要break语句来跳出判断,Scala从前往后匹配到一个分支后,会自动跳出判断

除了匹配特定的常量,还能匹配某种类型的所有值

    for (elem <- List(6, 9, 0.618, "Spark", "Hadoop", 'Hello)) {
      val str = elem match {
        case i: Int => i + " is an int value." //匹配整型的值,并赋值给i
        case d: Double => d + " is a double value." //匹配浮点型的值
        case "Spark" => "Spark is found." //匹配特定的字符串
        case s: String => s + " is a string value." //匹配其它字符串
        case _ => "unexpected value:" + elem //与以上都不匹配
      }
      println(str)
    }

【Scala】面向对象编程_java_19
可以在match表达式的case中使用守卫式(guard)添加一些过滤逻辑

    for (elem <- List(1, 2, 3, 4)) {
      elem match {
        case _ if (elem % 2 == 0) => println(elem + " is even.")
        case _ => println(elem + " is odd.")
      }
    }

case

case类是一种特殊的类,它们经过优化以被用于模式匹配

当定义一个类时,如果在class关键字前加上case关键字,则该类称为case

Scalacase类自动重载了许多实用的方法,包括toStringequalshashcode方法

Scala为每一个case类自动生成一个伴生对象,其包括模板代码

  • 1个apply方法,因此,实例化case类的时候无需使用new关键字

  • 1个unapply方法,该方法包含一个类型为伴生类的参数,返回的结果是Option类型,对应的类型参数是N元组,N是伴生类中主构造器参数的个数。Unapply方法用于对对象进行解构操作,在case类模式匹配中,该方法被自动调用,并将待匹配的对象作为参数传递给它

假如自定义一个如下的case

case class Car(brand :String,price: Int)

那么编译器自动生成的半生对象是

object  Car{
  def apply(brand:String,price:Int)= new Car(brand,price)
  def unapply(c:Car):Option[(String,Int)]=Some((c.brand,c.price))
}
object CaseTest {
  def main(args: Array[String]): Unit = {
    val myBYDCar = Car04("BYD", 89000)
    val myBMWCar = Car04("BMW", 1200000)
    val myBenzCar = Car04("Benz", 1500000)
    for (car <- List(myBYDCar, myBMWCar, myBenzCar)) {
      car match {
        case Car04("BYD", 89000) => println("Hello, BYD!")
        case Car04("BMW", 1200000) => println("Hello, BMW!")
        case Car04(brand, price) => println("Brand:" + brand + ", Price:" + price + ", do you want it?")
      }
    }
  }
}

case class Car04(brand: String, price: Int)

【Scala】面向对象编程_java_20

跳转顶部


为了解决程序中命名冲突的问题,Scala也采用包来层次化、模块化的组织程序

package autodepartment
class MyClass

为了在任意位置访问到MyClass,则需要写成下列格式autodepartment.MyClass

通过在关键字package后面加大括号,可以将程序的不同部分放在不同的包里。这样可以实现包的嵌套,相应的作用域也是嵌套的

package xmu {
  package autodepartment {
    class ControlCourse{
      ...
    }
  }
  package csdepartment {
    class  OSCourse{
      val cc = new autodepartment.ControlCourse
    }
  }
}

使用import自居来引用包成员

import xmu.autodepartment.ControlCourse
class MyClass{
  var myos=new ControlCourse
}

使用通配符(_)引入类或对象的所有成员

import scala.io.StdIn._
var i=readInt()
var f=readFloat()
var str=readLine()

跳转顶部