Scala面向对象【下】

news/2024/10/22 17:30:45/

 1、特质

  • Scala 语言中,采用特质 trait(特征)来代替接口的概念,也就是说,多个类具有相同的特质(特征)时,就可以将这个特质(特征)独立出来,采用关键字 trait 声明。
  • Scala 中的 trait 中既可以有抽象属性和方法,也可以有具体的属性和方法,一个类可以混入(mixin)多个特质。这种感觉类似于 Java 中的抽象类。
  • Scala 引入 trait 特征,第一可以替代 Java 的接口,第二个也是对单继承机制的一种补充。

1.1、特质的声明

基本语法

trait 特质名 {trait 主体
}

重写冲突属性案例

  • 一个类具有某种特质(特征),就意味着这个类满足了这个特质(特征)的所有要素,所以在使用时,也采用了 extends 关键字,如果有多个特质或存在父类,那么需要采用 with 关键字连接(相当于 Java 的 implements )。
  • 如果一个类既继承了一个父类又继承了一个特质,那么如果这个父类和特质又相同的属性,在访问该属性时就会产生冲突,子类需要重写该属性。
class Person13{val name: String = "person"val age: Int = 20def sayHello(): Unit ={println("hello " + name)}
}//定义一个特质
trait Young {//声明一个非抽象属性val name: String = "young"//声明一个抽象方法def study(): Unit//声明一个非抽象方法def play(): Unit = {println("play")}}class Student13 extends Person13 with Young {//重写冲突属性override val name = "young student"//实现抽象方法def study(): Unit = {println(s"student ${name} like study")}//重写父类方法override def sayHello(): Unit = {super.sayHello()println(s"hello student ${name}")}}

1.2、动态混入

动态混入,也就是在创建对象的时候再去继承特质实现抽象属性和方法。

object Test {def main(args: Array[String]): Unit = {//动态混入 创建对象时灵活扩展特质val student1 = new Student13 with sexTrait {//实现抽象属性 val 不可变更为 varval sex = "young student"}//调用混入的trait属性student1.sex}}class Person13{val name: String = "person"val age: Int = 20def sayHello(): Unit ={println("hello " + name)}
}//声明一个特质
trait sexTrait {val sex: String
}class Student13 extends Person13{//重写父类方法override def sayHello(): Unit = {super.sayHello()println(s"hello student ")}}

1.3、特质叠加

        由于一个类可以混入(mixin )多个 trait ,且 trait 中可以有具体的属性和方法,若混入的特质中具有相同的方法(方法名,参数列表,返回值均相同),必然会出现继承冲突问题。冲突分为以下两种:
  • 第一种,一个类(Sub)混入的两个 traitTraitATraitB)中具有相同的具体方法,且两个 trait 之间没有任何关系,解决这类冲突问题,直接在类(Sub)中重写冲突方法。

 

trait A{val num: Intdef fun(): Unit = {println("A")}
}trait B{val num: Int = 10def fun(): Unit = {println("B")}
}
class Student14 extends Person13 with A with B{//重写方法 funoverride def fun(): Unit = {super.fun() //最后继承的特质是B 所以fun方法会调用B的fun方法}}object Test14_TraitOverlying {def main(args: Array[String]): Unit = {val stu = new Student14stu.fun() //输出 Bprintln(stu.num)    //10}
}

特质叠加的顺序

        特质A和B中都含有变量num,但是特质A并没有初始化num的值,而特质B初始化了num的值。正因为最后继承了特质B,而特质B中实现了num变量的赋值,所以我们在子类中不需要实现或者重写num的值,可以直接访问num的值,这时候访问到的也就是特质B中初始化的值。

        如果A也初始化了num的值,则B无法叠加。

        如果A初始化了num的值,B没有,尽管最后继承的是特质B,但B仍然无法覆盖num,所以访问到的是A定义的num的值。

trait horse{val name: String = "马"
}
trait donkey{val name: String 
}class Animal{}//骡子
class Mule extends Animal with horse with donkey {}object Test {def main(args: Array[String]): Unit = {val mule = new Muleprintln(mule.name)    //马}}
trait horse{val name: String
}
trait donkey{val name: String = "驴"
}class Animal{
}//骡子
class Mule extends Animal with horse with donkey {}object Test {def main(args: Array[String]): Unit = {val mule = new Muleprintln(mule.name)    //驴}}
  • 第二种,一个类(Sub)混入的两个 traitTraitATraitB)中具有相同的具体方法,且两个 trait 继承自相同的 traitTraitC),及所谓的“钻石问题”,解决这类冲突问题,Scala 采用了特质叠加的策略

object Test {def main(args: Array[String]): Unit = {val mule = new Muleprintln(mule.describe())    //骡子是 驴-马-爬行动物}}trait horse extends crawler {val t1: String = "马-"override def describe(): String = t1 + super.describe()
}
trait donkey extends crawler {val t2: String = "驴-"override def describe(): String = t2 + super.describe()
}//爬行动物特征
trait crawler {def describe(): String = {"爬行动物"}
}//骡子
class Mule extends horse with donkey {override def describe(): String = "骡子是 " + super.describe()
}

特质叠加顺序:骡子 -> 驴 -> 马 -> 爬行动物 

指定父类的方法

        直接 super[父类].方法名,这样就不会去使用叠加后的方法,而是直接使用我们指定的子类的某个父类的方法,不用担心被叠加的问题

class Mule extends horse with donkey {override def describe(): String = "骡子是 " + super[horse].describe()
}
object Test {def main(args: Array[String]): Unit = {val mule = new Muleprintln(mule.describe())    //骡子是 马-爬行动物}
}

super关键字

        在Scala中,super关键字只能用于调用父类的方法,不能用于访问或调用父类的属性。这是因为在Scala中,属性访问器(gettersetter)实际上是方法的一种特殊形式。如果需要在子类中访问父类的属性,你可以在父类中定义一个公共的方法(getter方法)来返回属性的值。然后在子类中通过调用该方法来获取父类的属性值。

1.4、自身类型

自身类型实现了 依赖注入 的功能。

案例-用户注册

package chapter06object Test16_SelfType {def main(args: Array[String]): Unit = {val user = new RegisterUser("tom","123456")user.register()}}class User(val name: String,val password: String)trait UserDao{//把自身类型定义为User 相当于我们已经有一个User实例对象 直接在这操作_: User =>def register(): Unit = {val res =s"""|注册成功!|用户名: ${this.name}|密码:   ${this.password}|""".stripMarginprintln(res)}
}class RegisterUser(name: String,password: String) extends User(name, password) with UserDao
注册成功!
用户名: tom
密码:   123456

1.5、扩展

类型的检查与转换

  1. obj.isInstanceOf[T]:判断 obj 是不是 T 类型。
  2. obj.asInstanceOf[T]:将 obj 强转成 T 类型。
  3. classOf: 获取对象的类名。

枚举和应用类

枚举类:需要继承 Enumeration
应用类:需要继承 App
object Test {def main(args: Array[String]): Unit = {println(WorkDay.MONDAY) //Mondayprintln(WorkDay.TUESDAY) //Tuesday}
}//定义枚举类对象
object WorkDay extends Enumeration{val MONDAY = Value(1,"Monday")val TUESDAY = Value(2,"Tuesday")
}//定义应用类对象 不需要main方法 直接就可以运行
object TestApp extends App{println("app start")
}

Type 

使用 type 关键字可以定义新的数据数据类型名称,本质上就是类型的一个别名
 type Str = Stringval word: Str = "hello"print(word)


http://www.ppmy.cn/news/688153.html

相关文章

【分布式存储】聊聊共识和一致性

在分布式存储系统中,对于提高性能、可用性、可拓展性来说都有相关机制可以保证,比如复制、切片等,但是一旦涉及到分布式系统中选主的问题,就比较难,因为网络是不可靠的,并且可能还有拜占庭将军问题。所以如…

MS5182N(AD7682)驱动开发调试总结(一)

简介 MS5182N芯片是瑞盟科技的一款4通道的16位SAR ADC芯片,其对标的是ADI的AD7682芯片,或者说基本上两者功能一样,可以作为国产替代。另外其MS5189(8通道的)对标的则是AD7689。我此次项目中仅使用了MS5182N 。不过还是吐槽一下,其数据手册做的真是无语,虽然明显有直…

STM32与多台MS5803压力传感器I2C通讯

MS5803压力传感器支持SPI和I2C总线通讯,拥有24位AD转换。能够同时获得压力值和温度值,其中压力测量范围为10-1100mbar,温度的测量范围是-40-85摄氏度。各引脚功能及参数如下: 传感器内部结构图如下: 通讯协议的选择通过…

STM32F4实时时间精确到ms

开发板:STM32F407 1.目的:在屏幕上能显示的实时时间精确到ms,如 时 :分:秒:毫秒; 2.方式:RTC结合systick定时器,由于RTC只能为秒级,所以毫秒需要利用systic…

stm32实现毫秒ms微秒us级延时

stm32实现毫秒ms微秒us级延时 上一篇文章简单捋了一下32时钟初始化的过程,对systick嘀嗒定时器有了一定的了解吧 实现方法有很多种,推荐一个博客:https://blog.csdn.net/u011878611/article/details/107304203/ 我自己在此基础上实现的贴一…

外设驱动库开发笔记17:MS5803压力变送器驱动

很多时候我们需要检测被控对象的绝对压力,而且在我们的多款产品中也有这样的需求。当然检测绝对压力的传感器有很多,我们经常使用MS5803来实现压力检测。本篇中我们将设计并实现MS5803系列压力传感器的驱动。 1、功能概述 MS5803系列产品包含压阻传感器…

STM32 模拟IIC驱动MS5607气压传感器调试记录

标题 STM32 模拟IIC驱动MS5607调试记录 因项目需求,需使用MS5607的作为检测气压,再此写下自己遇见的问题以及调试记录。 硬件原理图如下: IIC接口总线使用了气压传感器,SHT35温度传感器,调试MS5607硬件的7位地址是0…

OPERA-MS:宏基因组二、三代测序混合组装

之前详细介绍了宏基因组二、三代混合组装软件OPERA-MS的Nature Biotechnology文章。详见下文: NBT:宏基因组二、三代混合组装软件OPERA-MS 今天带来软件的使用经验,主要参考如下官方文档: https://github.com/CSB5/OPERA-MS 同时使…