Scala 基础 :面向对象(下篇)

Posted 百思不得小赵

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Scala 基础 :面向对象(下篇)相关的知识,希望对你有一定的参考价值。

在之前的文章中总结了Scala面向对象模块基础的内容,接下来学习面向对象的高阶内容。

一、抽象类

如何定义?

// 定义抽象类
abstract class 类名
    // 定义抽象属性 不赋初始值
    val|var 变量名: 类型
    // 定义抽象方法  只声明,不实现
    def 方法名(): 返回值类型
  • 如果父类为抽象类,那么子类需要将抽象的属性和方法实现,否则子类也需声明为抽象类
  • 重写非抽象方法需要用 override 修饰,重写抽象方法则可以不加 override
  • 子类中调用父类的方法使用 super 关键字
  • 子类对抽象属性进行实现,父类抽象属性可以用 var 修饰;
  • 子类对非抽象属性重写,父类非抽象属性只支持 val 类型,而不支持 var。因为var修饰为可变量,子类继承后可以直接使用修改,没有必要重写。

举个栗子:

// 定义抽象类
abstract class Person
  // 定义非抽象属性
  val name: String = "person"
  // 抽象属性
  var age: Int

  // 非抽象方法
  def eat(): Unit =
    println("Person eat")
  

  // 抽象方法
  def sleep(): Unit


class Student extends Person
  // 实现抽象属性和方法
   var age: Int = 18

   def sleep(): Unit =
    println("student sleep")
  

  // 重写非抽象属性和方法
  override val name: String = "Student"

  override def eat(): Unit = 
    super.eat()
    println("Student eat")
  

匿名子类

和 Java 一样,可以通过包含带有定义或重写的代码块的方式创建一个匿名的子类。匿名子类只针对抽象类和接口。

举个栗子:

object Test10_AnnoymousClass 
  def main(args: Array[String]): Unit = 
    // 匿名子类实现
    val person = new Person 
      override var name: String = "alice"

      override def eat(): Unit = println("person eat")
    

    println(person.name)
    person10.eat()
  


abstract class Person 
  var name: String
  def eat():Unit

二、单例对象(伴生对象)

Scala是一门完全面向对象的语言,没有静态操作。为了能够和Java语言进行交互,使用单例对象来取代static关键字的语义,伴生类的静态声明都可放在伴生对象中。

基本语法:

object 伴生对象名
    val country: String="China"
  • 编译后会生成两个类,伴生对象是伴生类(类名为对应类后加$符号)的单例对象。
  • 单例对象对应的类称之为伴生类,伴生对象的名称应该和伴生类名一致,必须在同一个文件中。
  • 单例对象中的属性和方法都可以通过伴生对象名(类名)直接调用访问。
  • Scala 中 obj(arg)的语句实际是在调用该对象的 apply 方法,即 obj.apply(arg)。用以统一面向对象编程和函数式编程的风格。
  • Scala底层对于伴生对象的apply方法进行了优化,调用时可以省略方法名,直接使用单例对象的名称+调用apply方法的参数
  • 当使用 new 关键字构建对象时,调用的其实是类的构造方法,当直接使用类名构建对象时,调用的其实时伴生对象的 apply 方法

    举个栗子:

// 伴生类
// 构造器私有化
class Student private(val name: String, val age: Int) 
  def printInfo(): Unit = 
    println(s"Student11: $name $age $Student11.school")
  


// 伴生对象
object Student 
  // 看作静态的属性
  val school: String = "清华"
  // 定义类对象实例创建的方法
  def newStudent(name: String,age: Int): Student11 = new Student11(name,age)

  def apply(name: String, age: Int): Student11 = new Student11(name, age)


object Test11_Object 
  def main(args: Array[String]): Unit = 
    val student = Student.newStudent("alice", 12)
    student.printInfo()

    val student1 = Student.apply("haha", 12)

    val student2 = Student("lolo", 34)
    student2.printInfo()
  

三、特质

如何定义特质?

trait 特质名 
    // 代码块
  • Scala 语言中,采用特质 trait(特征)来代替接口的概念
  • 多个类具有相同的特征时,就可以将这个特征提取出来,用继承的方式来复用
  • Scala 中的 trait 中即可以有抽象属性和方法,也可以有具体的属性和方法,一个类可以混入(mixin)多个特质。这种感觉类似于 Java 中的抽象类。

基本语法:

有父类 class extends baseClass with trait1 with trait2 ... 
没有父类 class extends trait1 with trait2 ... 
  • 如果一个类在同时继承特质和父类时,应当把父类写在 extends 后。
  • 特质中可以定义抽象和非抽象的属性和方法。

特质叠加引发两种冲突

举个栗子:

class Person 
    val name: String = "Person"
    var age: Int = 18

    def sayHi(): Unit = 
        println(s"hello from : $name")
    


trait Young 
    // abstract and non-abstract attribute
    var age: Int
    val name: String = "young"

    // method
    def play(): Unit = 
        println(s"young people $name is playing")
    
    def dating(): Unit


trait Knowledge 
    var amount: Int = 0
    def increase(): Unit = 
        amount += 1
    


trait Talent 
    def increase(): Unit = 
        println("increase talent")
    


class Student extends Person with Young with Knowledge with Talent
    override val name: String = "alice"

    def dating(): Unit = 
        println(s"Sutdent $name $age is dating")
    

    def study(): Unit = println(s"Student $name is studying")

    override def sayHi(): Unit = 
        super.sayHi()
        println(s"hello from : student $name")
    

    override def increase(): Unit = 
        super.increase() 
        println(s"studnet $name knowledge increase: $amount")
    


object Trait 
    def main(args: Array[String]): Unit = 
        val s = new Student()
        s.sayHi()
        s.increase()

        s.study()
        s.increase()

        s.play()
        s.increase()

        s.dating()
        s.increase()
    

举个栗子:

trait Ball 
  def describe(): String = "ball"


trait ColorBall extends Ball 
  val colorBall: String = "red"

  override def describe(): String = 
     colorBall+"-----"+super.describe()
  


trait CategoryBall extends Ball
  val categoryBall: String = "foot"

  override def describe(): String = categoryBall+"-----"+super.describe()


// 叠加顺序 MyFootBall -> ColorBall -> CategoryBall -> Ball
class MyFootBall extends CategoryBall with ColorBall 
  override def describe(): String = "my ball is a" + super.describe()
  • 当一个类混入多个特质的时候,scala 会对所有的特质及其父特质按照一定的顺序进行排序,而此案例中的super.describe()调用的实际上是排好序后的下一个特质中的 describe()方法。
  • 要调用某个指定的混入特质中的方法,可以增加约束:super[]
    super[CategoryBall].describe()

自身类型

  • 自身类型可实现依赖注入的功能。
  • 一个类或者特征指定了自身类型的话,它的对象和子类对象就会拥有这个自身类型中的所有属性和方法。
  • 是将一个类或者特征插入到另一个类或者特征中,属性和方法都就像直接复制插入过来一样,能直接使用。但不是继承,不能用多态。

举个栗子:

object Test16_TraitSelfType 
  def main(args: Array[String]): Unit = 
    val user = new RegisterUser("alice", "1212121")
    user.insert()
  


// 用户类
class User(val name: String,val password: String)



trait UserDao
  // 定义自身类型
  _: User =>
  // 注册用户
  def insert():Unit=
    println (s" insert into db: = $this.name , $this.password")
  


 // 定义注册用户
class RegisterUser(name: String,password: String) extends User(name,password) with UserDao
  • _: SelfType =>,其中_的位置是别名定义,也可以是其他,_指代this。插入后就可以用this.xxx来访问自身类型中的属性和方法了。

抽象类和特质的区别?

四、扩展内容

类型检查和转换

  • obj.isInstanceOf[T]:判断 obj 是不是 T 类型。
  • obj.asInstanceOf[T]:将 obj 强转成 T 类型
  • classOf 获取对象的类名。结果是class package.xxx.className
  • 获取对象的类:obj.getClass

枚举类

  • 需要继承 Enumeration
  • Value类型定义枚举值。
// 定义枚举类
object WorkDay extends Enumeration
  val MONDAY = Value(1,"星期一")
  val TUESDAY = Value(2,"星期二")


    println(WorkDay.MONDAY)

应用类

  • 继承App,包装了main方法,就不需要显式定义main方法了,可以直接执行。
object TestApp extends App
  println("app start"

定义新类型

  • 使用 type 关键字可以定义新的数据数据类型名称,本质上就是类型的一个别名
  • type SelfDefineType = TargetType
 type MyString= String
  val a: MyString = "abc"
  println(a)

本次分享的内容到这里就结束了,希望对大家学习Scala语言有所帮助!!!

以上是关于Scala 基础 :面向对象(下篇)的主要内容,如果未能解决你的问题,请参考以下文章

2021年大数据常用语言Scala(三十一):scala面向对象 特质(trait)

Scala学习三-面向对象

scala入门笔记

Scala从基础到开发实战

scala

Scala语言入门