Scala详解(4)

embedded/2024/10/18 14:24:38/

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.ppmy.cn/embedded/8987.html

相关文章

android 接收到的json字段为null处理

1. 接收到JSON数据 首先&#xff0c;我们需要在Android应用中接收到一个包含JSON数据的字符串。可以使用以下代码将JSON字符串转换为JSONObject对象&#xff1a; String jsonString "Your JSON String"; JSONObject jsonObject new JSONObject(jsonString); 2. 解…

软考134-上午题-【软件工程】-进度管理

一、甘特图&#xff08;了解&#xff09; 1-1、定义 Gantt图是一种简单的水平条形图&#xff0c;它以日历为基准描述项目任务。 水平轴表示日历时间线(如时、天、周、月和年等)&#xff0c;每个条形表示一个任务&#xff0c;任务名称垂直地列在左边的列中&#xff0c;图中水…

优维应用级数字化架构管理:让企业运维天堑变通途

在优维科技的产品视角中&#xff0c;数字化架构管理就像是一门精妙的艺术&#xff0c;它将上层应用模型的业务概念以可视化的方式呈现出来&#xff0c;使得业务逻辑和流程变得更加直观、清晰。我们将这样的管理方式理解为“给企业搭起一座桥梁”——在这座桥梁的搭建过程中&…

springsecurity-权限控制

一&#xff0c;**需求&#xff1a; **用户没有登录的时候&#xff0c;导航栏上只显示登录按钮&#xff0c;用户登录之后&#xff0c;导航栏可以显示登录的用户信息及注销按钮&#xff01;还有就是&#xff0c;比如admin这个用户&#xff0c;它只有 vip2&#xff0c;vip3功能&a…

Java——三层架构

在我们进行程序设计以及程序开发时&#xff0c;尽可能让每一个接口、类、方法的职责更单一些&#xff08;单一职责原则&#xff09;。 单一职责原则&#xff1a;一个类或一个方法&#xff0c;就只做一件事情&#xff0c;只管一块功能。 这样就可以让类、接口、方法的复杂度更低…

Activiti——将绘制的流程图存入act数据库并进行流程推进与状态流转

文章目录 前言流程图入库操作 RepositoryService项目结构数据库连接配置文件入库Java测试代码zip 方式进行流程的批量部署 流程启动 RuntimeService待处理任务查看 TaskService流程状态的扭转查询流程定义信息 RepositoryService查询正在执行的流程实例 RuntimeService已部署流…

单机单实例部署Kafka及测试

文章目录 部署Docker 测试启动测试创建Topic生产者消费者 集成Manager的部署dockerfile效果 参考资料 在我们做和kafka开发相关的工作时&#xff0c;往往希望独立部署一套kafka测试环境。而kafka部署时&#xff0c;不能只是简单安装kafka自身组件&#xff0c;还要安装zookeeper…

Flutter开发之--初识Flutter

文章目录 概述Flutter整体架构嵌入层引擎层框架层 跑通demo尝鲜Flutter项目的目录介绍Flutter demo项目的运行 总结 概述 Flutter 是由Google公司研发的一种跨端开发技术&#xff0c;在2018年正式推出。Flutter自带Skia图形绘制引擎&#xff0c;采用自绘制的方式&#xff0c;不…