Scala详解(4)

Scala

面向对象

案例

  1. 定义类表示矩形(Rectangle),提供对外获取周长(girth)和面积(area)的函数,并且为这个矩形类提供一个子类表示正方形(Square)

    package com.fesco.exer
    ​
    object ObjectDemo1 {
    ​def main(args: Array[String]): Unit = {
    ​val r = new Rectangle(5.2, 8.5)println(r.girth)println(r.area)
    ​val s = new Square(4.8)println(s.girth)println(s.area)
    ​}
    ​
    }
    ​
    // 定义一个类表示矩形
    // 矩形肯定要包含两个属性:height和width
    // 矩形定义好之后,宽和高不能发生改变
    // 定义在构造器中的常量属性,允许在创建对象的时候给值
    class Rectangle(val height: Double, val width: Double) {
    ​def girth: Double = (height + width) * 2
    ​def area: Double = height * width
    ​
    }
    ​
    // 子类:正方形
    class Square(override val width: Double) extends Rectangle(width, width)

抽象类和抽象方法

  1. 在Scala中,依然是通过abstract来定义抽象类。不同的地方在于,Scala中不需要使用abstract来定义抽象方法;如果一个方法在定义的时候没有函数体,那么默认就是抽象方法,不需要写abstract

  2. Scala中,抽象类中还可以定义抽象属性!!!

  3. 案例

    // 定义类表示图形Shape
    // 凡是图形,都应该有获取面积和周长的方法
    // 问题在于,不同的图形,获取面积和周长的方式是不同的
    // 那么也就意味着,需要在Shape中提供函数来获取面积和周长
    // 但是函数不需要具体的实现,而是由不同的子类来具体实现
    abstract class Shape {
    ​// 抽象属性// 子类继承抽象类的时候来覆盖这个属性// 抽象属性,就意味着子类必须有这个属性,但是父类不确定这个属性的值val versionUID: Long
    ​// 周长def girth: Double
    ​// 面积def area: Double
    ​
    }

  4. 抽象类中可以包含抽象方法和实体方法

  5. 子类继承抽象类,就需要覆盖其中的抽象函数

    package com.fesco.abstractx
    ​
    object AbstractDemo1 {
    ​def main(args: Array[String]): Unit = {
    ​val s:Shape = new Circle(5)println(s.area)println(s.girth)
    ​}
    ​
    }
    ​
    // 定义类表示图形Shape
    // 凡是图形,都应该有获取面积和周长的方法
    // 问题在于,不同的图形,获取面积和周长的方式是不同的
    // 那么也就意味着,需要在Shape中提供函数来获取面积和周长
    // 但是函数不需要具体的实现,而是由不同的子类来具体实现
    abstract class Shape {
    ​// 抽象属性// 子类继承抽象类的时候来覆盖这个属性// 抽象属性,就意味着子类必须有这个属性,但是父类不确定这个属性的值val versionUID: Long
    ​// 周长def girth: Double
    ​// 面积def area: Double
    ​
    }
    ​
    // 圆形
    class Circle(val radius: Double) extends Shape {
    ​override val versionUID: Long = 4589512675L
    ​override def girth: Double = 2 * radius * Math.PI
    ​override def area: Double = Math.PI * radius * radius
    }

伴生对象(object)

  1. 在Java中,提供了static表示静态,可以通过类来调用静态属性或者静态方法,但是Scala作为一门完全面向对象的语言,认为静态是不合理的,因为静态和对象是无关的,Scala就认为static破坏了面对象对象的原则,因此Scala干脆不支持static

  2. 为了实现和static类似的效果,在Scala提供了伴生对象(object)。可以为每一个类提供一个同名的object(伴生对象),定义在伴生对象中的属性和函数,在编译之后会自动变成静态的。此时和object同名的类称之为伴生类

    // 伴生类
    class Person{}
    // 伴生对象
    object Person{}
  3. 伴生类和伴生对象必须同名,编译的时候才会编译到一个class文件中

    package com.fesco.objectx
    ​
    object CalcDemo {
    ​def main(args: Array[String]): Unit = {
    ​// add可以通过类名来调用println(Calculator.add(5, 8))// test必须通过对象来调用val c = new Calculatorc.test()
    ​}
    ​
    }
    ​
    object Calculator {
    ​def add(x: Int, y: Int): Int = x + y
    ​
    }
    ​
    class Calculator {
    ​def test(): Unit = println("running")
    ​
    }

  4. 案例:单例模式

    package com.fesco.objectx
    ​
    object SingletonDemo {
    ​def main(args: Array[String]): Unit = {
    ​val a = A.getInstanceprintln(a)val b = B.getInstanceprintln(b)
    ​}
    ​
    }
    ​
    // 单例模式:全局过程中只存在唯一实例
    // 不能对外创建对象 - 构造器私有化
    class A private()
    ​
    // 定义伴生对象
    object A {// 提供本类对象,一般不会直接对外操作,所以需要私有化// 饿汉式private val a = new A
    ​// 对外提供函数来获取这个对象def getInstance: A = a
    }
    ​
    class B private()
    ​
    object B {private var b: B = _
    ​// 懒汉式def getInstance: B = {if (b == null) b = new Bb}
    }

特质/特征(trait)

  1. 在Scala中,没有接口的说法,而是提供了类似的机制:trait

  2. 定义结构

    trait 特质名 {特质体
    }
  3. 不同于Java的地方在于,特质中可以有抽象方法和抽象属性,也可以有实体方法和实体属性

  4. 在Scala中,一个类可以混入(mixin)多个特质!所以,特质可以看作是对单继承的补充

  5. 注意:在Scala中,如果一个类本身没有继承父类,那么在混入一个特质的时候需要使用extends,混入其他特质的时候使用with

    package com.fesco.traitx
    ​
    object TraitDemo {
    ​def main(args: Array[String]): Unit = {
    ​val s = new Students.study()s.break()s.play()
    ​}
    ​
    }
    ​
    trait Study {// 抽象函数def study(): Unit
    }
    ​
    trait Break {def break(): Unit
    }
    ​
    trait Play {def play(): Unit
    }
    ​
    // 没有父类
    // 使用第一个特质的时候,需要使用extends关键字
    // 类混入特质之后,需要覆盖特质中的抽象方法
    // 从第二个特质开始,需要使用with来关联
    class Student extends Study with Break with Play {
    ​override def study(): Unit = println("学习中~~~")
    ​override def break(): Unit = println("休息中~~~")
    ​override def play(): Unit = println("玩耍中~~~")
    }

  6. 如果一个类本身已经有了父类,那么此时所有的特质只能使用with来混入

    package com.fesco.traitx
    ​
    object TraitDemo2 {
    ​def main(args: Array[String]): Unit = {
    ​val c = new Circle(5)println(c.girth)println(c.area)
    ​}
    ​
    }
    ​
    trait Girth {def girth: Double
    }
    ​
    trait Area {def area: Double
    }
    ​
    class Shape {val name: String = "Shape"
    }
    ​
    // 如果一个类本身已经有了父类,那么此时所有的特质只能使用with来混入
    class Circle(val r: Double) extends Shape with Girth with Area {
    ​override val name: String = "Circle"
    ​override def girth: Double = 2 * Math.PI * r
    ​override def area: Double = Math.PI * r * r
    }

  7. 需要注意的是,在Scala中,不只是类中可以混入特质,在声明对象的时候也可以单独的混入特质,这种方式称之为动态混入

    package com.fesco.traitx
    ​
    object TraitDemo3 {
    ​def main(args: Array[String]): Unit = {
    ​// Teacher对象 - 是否能够确定这个老师对应的科目// val t: Teacher = new Teacher// 就希望在定义对象的时候,能够顺便指定老师对应的科目val t1: Teacher with Chinese = new Teacher with Chinese {}println(t1.subject)val t2:Teacher with  Maths = new Teacher with Maths {}println(t2.subject)
    ​}
    ​
    }
    ​
    // 代表老师的类
    class Teacher
    ​
    // 语文课程
    trait Chinese {def subject: String = "语文"
    }
    ​
    // 数学课程
    trait Maths {def subject: String = "数学"
    }

  8. 正因为一个类中可以混入多个特质,且特质中还可以定义实体方法,所以在混入特质的时候就可能会产生冲突

    package com.fesco.traitx
    ​
    object TraitDemo4 {
    ​def main(args: Array[String]): Unit = {
    ​val d = new Dprintln(d.m(5))val e = new Eprintln(e.m(5))val f = new Fprintln(f.m(5))
    ​}
    }
    ​
    trait A {def m(x: Int): Int = x
    }
    ​
    trait B {def m(x: Int): Int = x * 2
    }
    ​
    trait C {def m(x: Int): Int = x * 3
    }
    ​
    // D混入特质A、B、C
    // 如果不指定,编译的时候会从右到左来依次寻找这个函数,只要能够找到,编译就不报错
    // 此时建议在类中重写这个函数
    class D extends A with B with C {override def m(x: Int): Int = x * 4
    }
    ​
    class E extends A with B with C {// 需要使用B特质的逻辑// 调用特质B中的m函数override def m(x: Int): Int = super[B].m(x)
    }
    ​
    // 不指定,那么会先使用C中的特质 --- 从右到左
    class F extends A with B with C {override def m(x: Int): Int = super.m(x)
    }

  9. 注意:如果混入了多个特质,且特质中有同名函数,但是函数的返回值类型不同,那么此时混入后会报错

    package com.fesco.traitx
    ​
    object TraitDemo5 {
    ​def main(args: Array[String]): Unit = {
    ​val t = new T3t.m(5)
    ​}
    ​
    }
    ​
    trait T1 {def m(x: Int): Int = x
    }
    ​
    trait T2 {def m(x: Int): Unit = println(x)
    }
    ​
    class T3 extends T1 with T2 {// 此时返回值无论是Unit还是Int都会报错// override def m(x: Int): Int = x * 2
    }

  10. 因此,在混入特质的时候,需要检查特质中的同名同参数列表的函数的返回值类型是否一致

  11. 在Java中,接口之间是可以通过extends来基础,同样,Scala中,trait之间也可以通过extends来继承

    trait A
    trait B extends A
  12. 正因为特质之间允许被继承,所以存在菱形继承的问题

    package com.fesco.traitx
    ​
    object TraitDemo6 {
    ​def main(args: Array[String]): Unit = {
    ​val s = new SubAprintln(s.m(5))
    ​}
    ​
    }
    ​
    trait SuperA {def m(x: Int): Int = x
    }
    ​
    // SubA1继承了特质SuperA
    trait SubA1 extends SuperA {override def m(x: Int): Int = x * 2
    }
    ​
    // SubA2继承了特质SuperA
    trait SubA2 extends SuperA {override def m(x: Int): Int = x * 3
    }
    ​
    // 由于SubA1和SubA2有共同的父特质,所以构成了菱形继承关系
    // 此时由于子特质SubA1和SubA2中重写了函数,没有调用父特质中的函数
    // 所以调用的时候是从右到左来寻找这个函数
    class SubA extends SubA1 with SubA2

  13. 菱形继承中的特质叠加

    package com.fesco.traitx
    ​
    object TraitDemo7 {
    ​def main(args: Array[String]): Unit = {
    ​val s = new SubBprintln(s.repeat("abc"))
    ​}
    ​
    }
    ​
    trait SuperB {
    ​def repeat(str: String): String = str
    ​
    }
    ​
    trait Sub1 extends SuperB {
    ​override def repeat(str: String): String = {println("Sub1 running ~~~")super.repeat(str) * 3}
    ​
    }
    ​
    trait Sub2 extends SuperB {
    ​override def repeat(str: String): String = {println("Sub2 running ~~~")super.repeat(str) + str}
    }
    ​
    // 如果混入了多个特质,且混入的特质之间有公共父特质,那么此时就会形成"特质叠加"现象:
    // 从右到左,Sub2中的super不是SuperB,而是Sub1,Sub1中的super才是SuperB
    class SubB extends Sub1 with Sub2

其他

自身类型(self-type)
  1. 自身类型,指的是在另一个类或者特质中指定一个其他类型,那么这个类或者这个特质的子类或者子特质就需要满足指定类型

    class 类名 {别名:类型 =>函数
    }
    // 或者
    trait 特质名 {别名:类型 =>函数
    }
  2. 案例

    package com.fesco.otherobject SelfTypeDemo {def main(args: Array[String]): Unit = {val r = new Register("Bob", "abc12343", "13547894512")r.register()}}// 代表用户的类
    class User(val username: String, val password: String, val phoneNumber: String)// 产生用户数据之后,需要将数据放入数据库中
    // 这个类负责和数据库来进行交互
    trait UserDao {// UserDao的子类或者子特质需要满足使用User类的要求// 凡是本类中使用到User的地方,都可以用u来表示User对象// u:User =>// 如果需要将User类和本类结合this: User =>def insert(): Unit = println(s"username:${this.username}, password:${this.password}, phone number:${this.phoneNumber}")
    }// 表示注册的类
    class Register(override val username: String, override val password: String, override val phoneNumber: String) extends User(username, password, phoneNumber) with UserDao {def register(): Unit = super.insert()
    }

APP类
  1. APP类是Scala中提供的一个特殊的特质。当一个类混入了APP之后,那么这个类就变成了一个快速启动类,利用这个特质,可以省略主函数的书写

    package com.fesco.otherobject APPDemo extends App {println("Hello world")}
type
  1. 在Scala中,可以通过type关键字来定义数据类型,其实就是给这个类起别名

    package com.fesco.otherobject TypeDemo {def main(args: Array[String]): Unit = {val d1: Double = 3.2println(d1)// 起别名// Double类型的别名就是Dtype D = Doubleval d2: D = 5.87println(d2)}}

枚举类
  1. 当一个类中有多个固定个数的实例,并且可以一一列举的时候 ,可以定义为枚举。例如:季节、星期、月份等

  2. 案例

    package com.fesco.otherobject EnumDemo {def main(args: Array[String]): Unit = {val w = Week.MONDAYprintln(w)// 获取这个类中的所有的枚举常量,然后放入一个Set集合中返回val values: Week.ValueSet = Week.valuesfor (elem <- values) {println(elem)}}}// 定义一个枚举表示星期
    // 在Scala中,没有enum关键字,而是通过object来定义枚举
    // 在Scala中,所有的枚举都有一个顶级父类:Enumeration
    object Week extends Enumeration {// val MONDAY = Value(1)// val MONDAY = Value("Monday")// 实际过程中,习惯上枚举常量都是大写的val MONDAY: Week.Value = Value(1, "Monday")val TUESDAY: Week.Value = Value(2, "Tuesday")val WEDNESDAY: Week.Value = Value(3, "Wednesday")val THURSDAY: Week.Value = Value(4, "Thursday")val FRIDAY: Week.Value = Value(5, "Friday")val SATURDAY: Week.Value = Value(6, "Saturday")val SUNDAY: Week.Value = Value(7, "Sunday")}

密封类(sealed)
  1. sealed是Scala中提供的一个特殊的关键字,可以用于修饰类或者特质。如果sealed修饰类或者特质,形成如下限制

    1. 被修饰的类或者特质的子类或者子特质必须必须和当前类处在同一个scala文件中,不能跨文件

    2. 被修饰的类或者特质参与模式匹配的时候,那么会进行检查,如果没有罗列所有的情况,那么会警告

  2. 案例

    package com.fesco.other
    
    
    object SealedDemo {
    }sealed trait Student {def study(): Unit
    }class Pupil extends Student {override def study(): Unit = println("小学生学习中")
    }

  3. sealed增强了封装特性

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

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

相关文章

永恒之蓝上线CS

该文介绍了在内网环境下&#xff0c;利用永恒之蓝漏洞&#xff08;EternalBlue&#xff09;将攻击者控制台&#xff08;CS&#xff09;上线的方法。前提条件是目标机器可上网、无防火墙和杀毒软件&#xff0c;并且存在永恒之蓝漏洞。使用Erebus插件的eterblue功能&#xff0c;通…

xpath的使用以及原理-元素定位

# 查找文本框输入文本 driver.find_element(By.CLASS_NAME,"nav-search-input").send_keys("i_cecream查找到了") #查找到之后点击 driver.find_element(By.CLASS_NAME,"nav-search-btn").click()time.sleep(30)selenium4的解析。 client调用se…

Kimi智能助手:您的个性化AI伙伴

目录 智能对话伙伴:kimi 功能部分 对话能力:多语言支持与深度交流

2024团体程序设计天梯赛L1-103 整数的持续性

题目链接L1-103 整数的持续性 #include<iostream> #include<stdio.h> #include<algorithm> using namespace std; struct node{int x;int d; }p[2000]; bool cmp(node a, node b) {if (a.d b.d) return a.x < b.x;return a.d>b.d; } int cnt, cntt; v…

信号----硬件中断

硬件中断 键盘组合键是向进程发送信号&#xff0c;那么键盘数据是如何输入到内核中&#xff0c;然后变成信号的&#xff1f;这个信号又是由谁发送给进程的&#xff1f; 当键盘被按下&#xff0c;操作系统先知道用户用键盘输入了内容 那么操作系统是如何知道键盘上有内容了&…

【Camera Sensor Driver笔记】二、点亮指南之Sensor Module XML

Camera Sensor module XML详解&#xff1a; cameraId 与 slot id 一一对应 &#xff08;即&#xff1a;dtsi中相对应的sensor的 cell-index &#xff09; moduleName 模组厂名称 sensorName sensor 名称 actuatorName 马达名称 oisName …

学习亚马逊云科技AWS云计算技术的三款官方免费3A游戏大作

玩3A大作免费电脑游戏&#xff0c;就能成为AWS云架构师、云开发大&#x1f42e;&#xff1f;这么好的事尊的假的&#xff1f;小李哥今天就来给大家介绍&#xff0c;如何通过玩AWS官方的定制版虚拟人生、炉石传说和密室逃脱游戏学习AWS。这三个游戏完全免费&#xff0c;没有任何…

如何利用pg_dump和pg_restore迁移从一个PostgreSQL服务器到另一个服务器,同时保持一致性与高效性?

文章目录 解决方案1. 使用pg_dump导出数据2. 将导出的数据复制到目标服务器3. 使用pg_restore导入数据保持一致性与高效性的策略一致性高效性 示例代码导出数据复制数据到目标服务器在目标服务器上解压并导入数据 PostgreSQL数据库的迁移是一个常见的任务&#xff0c;特别是在升…

如何在PostgreSQL中使用CTE(公共表表达式)来简化复杂的查询逻辑?

文章目录 解决方案步骤示例代码 结论 在处理复杂的SQL查询时&#xff0c;我们经常会遇到需要多次引用子查询或中间结果的情况。这可能会使得查询变得冗长且难以理解。为了解决这个问题&#xff0c;PostgreSQL&#xff08;以及其他一些SQL数据库系统&#xff09;引入了公共表表达…

springdoc-openapi使用

springdoc-openapi使用 一、引入pom二、新增配置类OpenApiConfig四、Controller层示例五、配置文件新增内容六、验证 一、引入pom <dependency><groupId>org.springdoc</groupId><artifactId>springdoc-openapi-ui</artifactId><version>1…

【WSL】单机大模型前的基础环境配置

前言&#xff1a;在上一篇文章中&#xff0c;我们完成了WSL的部署&#xff0c;但是在大模型搭建&#xff08;尤其是Langchain&#xff09;前&#xff0c;还碰到了不少的坑&#xff0c;查找了不少的文章&#xff0c;所以本篇文章就做一个记录&#xff0c;避免以后再走冤枉路。 …

并发编程 可见性、原子性和有序性,如何解决

可见性&#xff0c;原子性和有序性 CPU&#xff0c;内存&#xff0c;I/0 三者在速度上存在很大差异&#xff0c;大概是CPU耗时一天 内存耗时一年&#xff0c;内存耗时一天 /O耗时十年 CPU 增加了缓存&#xff0c;以均衡与内存的速度差异;操作系统增加了进程、线程&#xff0…

力扣第541题: 反转字符串 II

题目&#xff1a; 给定一个字符串 s 和一个整数 k&#xff0c;从字符串开头算起, 每计数至 2k 个字符&#xff0c;就反转这 2k 个字符中的前 k 个字符。 如果剩余字符少于 k 个&#xff0c;则将剩余字符全部反转。 如果剩余字符小于 2k 但大于或等于 k 个&#xff0c;则反转…

迎接大模型时代:程序员的挑战与应对

随着人工智能技术的迅猛发展&#xff0c;大模型已成为当前人工智能领域的重要趋势之一。大模型具有更强大的表征能力和泛化能力&#xff0c;已在自然语言处理、计算机视觉等领域取得了显著成果。然而&#xff0c;大模型的出现也给程序员带来了新的挑战和机遇。 大模型对程序员…

通过v-if渲染的element-ui表单,校验规则不生效的问题

因为form-item绑定验证事件是在mounted中进行的&#xff0c;规则变化后没有进行重新绑定验证事件&#xff0c;v-if渲染组件节点diff后被复用了&#xff0c;所以验证也就自然失效了 例如&#xff1a;通过动态选择类型来控制驾驶人是否显示&#xff0c;并且是必填项 给每一个el…

创建Vue项目后的初始化操作-解决Vue项目中盒子高度100%不生效问题

解决Vue项目中盒子高度100%不生效问题。 &#xff08;由于最近create的项目有点多&#xff0c;记录一下&#xff09;。 文章目录 方法一&#xff1a;对症下药方法二&#xff1a;偏方补充 方法一&#xff1a;对症下药 在项目根目录/public/index.html文件中的head里加入以下代码…

Java 与垃圾回收有关的方法

1. gc 调用垃圾回收器的方法是 gc&#xff0c;该方法在 System 类和 Runtime 类中都存在。 在 Runtime 类中&#xff0c;方法 gc 是实例方法&#xff0c;方法 System.gc 是调用该方法的一种传统而便捷的方法。在 System 类中&#xff0c;方法 gc 是静态方法&#xff0c;该方法…

oracle一次sql优化笔记

背景&#xff1a;两个百万级数据量表需要连接&#xff0c;加全索引的情况下速度仍不见改善&#xff0c;苦查一下午解决问题未遂。 解决&#xff1a;经大佬指点了解到oracle优化器提示&#xff0c;使用/* USE_HASH(table1 table2) */或者/* USE_MERGE(table1 table2) */来指导优…

P5732 【深基5.习7】杨辉三角

此题可以为杨辉三角&#xff0c;可以看一下这篇文章: 传送门 AC代码&#xff1a; #include<iostream>using namespace std;const int N 30; int arr[N][N];int main() {int n;cin >> n ;arr[1][1] 1;for(int i1;i<n;i){for(int j1;j<i;j){if(j 1 || j …

括号成对匹配

括号成对匹配 题目 括号成对匹配。例如&#xff1a;[a{b©d}e]匹配成功&#xff0c;a(b}匹配不成功 思路 这题的考察点是栈的原理&#xff0c;可以把括号匹配看成入栈和出栈&#xff0c;如果是左边的括号一律入栈&#xff1b;如果是右括号需要先与对应的左括号进行对比…