Scala面向对象【下】

news2024/11/18 23:40:34

 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 = 20

  def 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 不可变更为 var
      val sex = "young student"
    }

    //调用混入的trait属性
    student1.sex
  }

}

class Person13{
  val name: String = "person"
  val age: Int = 20

  def 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: Int
  def fun(): Unit = {
    println("A")
  }
}

trait B{
  val num: Int = 10
  def fun(): Unit = {
    println("B")
  }
}
class Student14 extends Person13 with A with B{

  //重写方法 fun
  override def fun(): Unit = {
    super.fun() //最后继承的特质是B 所以fun方法会调用B的fun方法
  }

}

object Test14_TraitOverlying {
  def main(args: Array[String]): Unit = {
    val stu = new Student14
    stu.fun() //输出 B
    println(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 Mule
    println(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 Mule
    println(mule.name)    //驴

  }

}
  • 第二种,一个类(Sub)混入的两个 traitTraitATraitB)中具有相同的具体方法,且两个 trait 继承自相同的 traitTraitC),及所谓的“钻石问题”,解决这类冲突问题,Scala 采用了特质叠加的策略

object Test {

  def main(args: Array[String]): Unit = {

    val mule = new Mule
    println(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 Mule
    println(mule.describe())    //骡子是 马-爬行动物

  }
}

super关键字

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

1.4、自身类型

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

案例-用户注册

package chapter06

object 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}
        |""".stripMargin

    println(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) //Monday
    println(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 = String
  val word: Str = "hello"
  print(word)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/694623.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

VSCode 关闭未修改文件编辑器的替换

文章目录 1 关闭编辑预览参考 1 关闭编辑预览 在setting中搜索preview取消enable Preview 选项[可选] 设置不同工作区 参考 vs code取消打开一个文件会替换之前未修改文件 https://blog.csdn.net/networkhunter/article/details/105043771

多个域名映射一个nginx多个80端口

阿里云多个二级域名,解析到同一个机器外网ip地址: http://demo.xxx.com.cn/ http://yang.xxx.com.cn/ nginx.conf 配置文件: server{listen 80;server_name yang.xxx.com.cn;# 第1个二级域名映射80端口index index.html index.htm index.ph…

【深度学习】6-2 卷积神经网络 - 池化层

池化是缩小高、长方向上的空间的运算。比如下图,将2 x 2的区域集约成1个元素的处理,缩小空间大小 上面的例子是按步幅2进行2x2的Max池化时的处理顺序。“Max池化”是获取最大值的运算,“2 x 2”表示目标区域的大小。从2x2的区域中取出最大的…

探索Gradio的Chatbot模块:创建交互式聊天机器人

❤️觉得内容不错的话,欢迎点赞收藏加关注😊😊😊,后续会继续输入更多优质内容❤️ 👉有问题欢迎大家加关注私戳或者评论(包括但不限于NLP算法相关,linux学习相关,读研读博…

构建高效学生志愿者活动管理系统:基于前后端分离的设计与实现

本文介绍了一种基于前后端分离的学生志愿者活动管理系统的设计与实现。通过前后端分离的架构,系统实现了高度可扩展性和灵活性,能够有效管理学生志愿者活动,并提供友好的用户界面。文章将详细介绍系统的架构设计、技术选型以及核心功能的实现,并给出相应的代码示例。 学生…

Linux——4linux实用操作

目录 4.1 各类小技巧(快捷键) 4.2 软件安装 4.3 systemctl 4.4 软连接 4.5 日期、时区 4.6 IP地址、主机名 IP地址 主机名 域名解析 配置主机映射 虚拟机配置固定IP 4.7 网络传输 下载和网络请求 端口 4.8 进程管理 4.9 主机状态 4.10 …

使用docx4j实现word转pdf

前言 word文件转pdf docx4j 将word转pdf 导入依赖 <dependency><groupId>org.docx4j</groupId><artifactId>docx4j-JAXB-Internal</artifactId><version>8.3.9</version></dependency><dependency><groupId>or…

计算机网络 - 第一章(下)

1.2_1 分层结构、协议、接口、服务_哔哩哔哩_bilibili1.2_1 分层结构、协议、接口、服务是王道计算机考研 计算机网络的第7集视频&#xff0c;该合集共计76集&#xff0c;视频收藏或关注UP主&#xff0c;及时了解更多相关视频内容。https://www.bilibili.com/video/BV19E411D78…

移远通信推出新款卫星通信模组CC660D-LS,加速IoT终端直连卫星

上海&#xff0c;2023年6月27日 — 在2023上海世界移动通信大会&#xff08;MWC Shanghai&#xff09;期间&#xff0c;全球领先的物联网整体解决方案供应商移远通信宣布&#xff0c;推出其在卫星通信领域的最新力作—— CC660D-LS 模组。该模组现阶段面向北美和欧洲市场&#…

【雕爷学编程】Arduino动手做(133)---LCD1602扩展板模块

7款传感器与执行器的提法&#xff0c;在网络上广泛流传&#xff0c;其实Arduino能够兼容的传感器模块肯定是不止这37种的。鉴于本人手头积累了一些传感器和执行器模块&#xff0c;依照实践出真知&#xff08;一定要动手做&#xff09;的理念&#xff0c;以学习和交流为目的&…

FDTD Solutions基础到精通,适用于微纳光学领域光学器件、超表面的仿真

专题二&#xff1a; “ FDTD 时域有限差分数值模拟方法与应用 课 程 内 容 FDTD基础入门 1 FDTD Solutions 求解物理问题的方法 1.1 FDTD与麦克斯韦方程 1.2 FDTD中的网格化 2 FDTD Solutions 特点与应用 3 FDTD功能与使用 主窗口——CAD人机交互界面计算机辅助设计…

SQL Server Management Studio (SSMS) 指定端口Port连接, 用逗号, 例如: localhost,1433

Microsoft SQL Server Management Studio (SSMS) 指定端口连接, 用,逗号, 例如 localhost,1433 localhost 等效 localhost,(逗号&#xff09;1433

使用项目跟踪工具,让项目管理更高效,使用项目管理工具的好处

为了确保项目按照预期规划完成&#xff0c;项目经理必须跟踪每个活动的进度。 项目跟踪是贯穿整个项目生命周期的重要活动&#xff0c;它可以通过有效的方式清晰地了解项目的实际进展情况。 项目管理工具可以帮助项目管理者实时跟踪项目状态&#xff0c;及时发现问题并跟踪解…

【springboot整合】Springboot和RedisCache

前面介绍了CacheAutoConfiguration默认生效的是SimpleCacheConfiguration配置类&#xff0c;实际中我们更多的是利用redis作为缓存&#xff0c;现在我们继续看看RedisCacheConfiguration有什么不同 原理分析 在引入redis相关依赖之后&#xff0c;对应的RedisCacheConfiguratio…

基于BS架构的汽车销售管理系统(源码+文档+报告+安装环境)

如今&#xff0c;越来越多的人愿意选择一种适合自己的管理方案&#xff0c;随着线上管理系统的快速兴起&#xff0c;大量的车辆信息被人们所熟知&#xff0c;而4S店车辆管理系统无疑是对4S店车辆进行管理的最好的系统。4S店车辆系统&#xff0c;为用户提供了一种可以让他们更好…

(16)燃油流量和液位传感器

文章目录 前言 16.1 燃油流量传感器 16.1.1 连接到自动驾驶仪 16.2 燃油液位传感器 16.2.1 PWM油位传感器 16.2.2 模拟油位传感器 前言 在 4.0 及以后的固件版本中&#xff0c;ArduPilot 提供了使用燃油流量和液位传感器的能力&#xff0c;此外还有电池监控器。支持脉冲输…

MongoDB复制集原理

复制集简介 Mongodb复制集由一组Mongod实例&#xff08;进程&#xff09;组成&#xff0c;包含一个Primary节点和多个Secondary节点&#xff0c;Mongodb Driver&#xff08;客户端&#xff09;的所有数据都写入Primary&#xff0c;Secondary从Primary同步写入的数据&#xff0…

Flink-窗口源码

滚动窗口底层只有一个窗口&#xff0c;每次用for循环&#xff0c;把前面过期的数据移除&#xff0c;留下的数据再进行计算 滑动窗口的时间窗口&#xff0c;是有多个window的&#xff0c;因为有重叠的数据 计数窗口、计数滑动窗口&#xff0c;底层只有一个窗口 会话窗口只有一…

视频融合平台EasyCVR电子地图增加鼠标悬停展示经纬度

EasyCVR可拓展性强、视频能力灵活、部署轻快&#xff0c;可支持的主流标准协议有GB28181、RTSP/Onvif、RTMP等&#xff0c;以及厂家私有协议与SDK接入&#xff0c;包括海康Ehome、海大宇等设备的SDK等&#xff0c;能对外分发RTSP、RTMP、FLV、HLS、WebRTC等格式的视频流。平台可…

结合底层源码介绍ConcurrentHashMap如何保证线程安全,佬会爱上这篇文章嘛

前言&#xff1a; 本篇文章主要讲解结合底层源码介绍ConcurrentHashMap如何保证线程安全的知识。该专栏比较适合刚入坑Java的小白以及准备秋招的大佬阅读。 如果文章有什么需要改进的地方欢迎大佬提出&#xff0c;对大佬有帮助希望可以支持下哦~ 小威在此先感谢各位小伙伴儿了…