文章目录

  • 四, Scala 伴生对象和伴生类
    • 4.1 单例对象和伴生对象
      • 4.1.1 什么是单例对象?
      • 4.1.2 如何使用Scala的伴生对象和伴生类来实现单例模式?
      • 4.1.2 apply方法
        • 4.1.2.1 什么是apply方法及其作用是什么?
    • 4.2 特质(Trait)
      • 4.2.1 特质的声明
    • 4.2.2 特质基本语法
    • 4.2.3 特质叠加
    • 4.2.4 特质叠加执行顺序
    • 4.2.5 特质和抽象类的区别
    • 4.2.6 特质自身类型

四, Scala 伴生对象和伴生类

4.1 单例对象和伴生对象

  • Scala语言是完全面向对象的语言, 所以并没有静态的操作(即在Scala中没有静态的概念, 没有静态变量, 静态方法等等);

  • 但是为了能够和Java语言交互(因为Java中有静态概念), Scala使用单例对象去模拟实现Java中的静态概念; 如何模拟呢? 让单例对象的名称与类的名称保持一致(即object A, class A, 类名为A, 保持一致), 这个单例对象呢, 也有了个新的名称, 我们称之为某个类的伴生对象;

  • (即, object A 本身是个单例对象, 但是由于和 class A类名一致了, 就把 object A 看作是 class A的伴生对象, class A叫伴生类);

  • 这里注意: 单例对象不等同于伴生对象噢!

4.1.1 什么是单例对象?

[基本语法]

object Person{val name: String = _
}

单例对象的特点

特点
1. 单例对象使用 object 关键字声明, 就像是定义一个类那样, objct Box
2. 单例对象对应的同名类叫伴生类, 特点就是伴生类和伴生对象同名
3.单例对象中的属性和方法都可通过伴生对象名(类名)直接调用访问
4. 当一个单例对象和某个类共享一个名称时,这个单例对象称为 伴生对象. 同理,这个类被称为是这个单例对象的伴生类。类和它的伴生对象可以互相访问其私有成员。

补充:

  1. 使用伴生对象来定义那些在伴生类中不依赖于实例化对象而存在的成员变量或者方法。
  2. 在 Java 中 static 成员对应于 Scala 中的伴生对象的普通成员。

[案例实操]

//(1)伴生对象采用 object 关键字声明
object Person {var country: String = "China"
}//(2)伴生对象对应的类称之为伴生类,伴生对象的名称应该和伴生类名一致。
class Person {var name: String = "bobo"
}object Test {def main(args: Array[String]): Unit = {//(3)伴生对象中的属性和方法都可以通过伴生对象名(类名)直接调用访
问。println(Person.country)}
}
  • 参考文章: Scala官方文档: 单例对象, 伴生对象

4.1.2 如何使用Scala的伴生对象和伴生类来实现单例模式?

我们先来简单的回顾一下Java或其他编程语言中学到的单例模式:

  • 具体文章: 单例模式的六种写法

[案例实操]

  • 前面我们知道了 object xx(单例对象)是Scala语言中专门处理静态成员的角色, 所以我们把静态私有单例类对象, 静态公有获取单例类对象的方法均放置在单例对象中;
  • 把私有的构造方法直接在类声明中体现出来 class xx private(){}, 即如果想让主构造器变成私有的, 可以在()之前加上private;
package SingletonPatternobject Singleton {//私有的静态的单例类实例对象var  singleton: Singleton = _//公有的静态的获取单例类对象的方法def getSingleton(): Singleton = {if(singleton == null)singleton = new Singleton()singleton}
}class Singleton private(){ //单例类的构造方法私有化println("伴生类的方法执行了")
}object Test{def main(args: Array[String]): Unit = {//获取单例对象var singleton1 = Singleton.getSingleton()var singleton2 = Singleton.getSingleton()println(singleton1) println(singleton2)}
}

4.1.2 apply方法

4.1.2.1 什么是apply方法及其作用是什么?

待补充
参考文章: 什么是apply?

apply()的定义和作用
1. apply目的是缩小Scala面向对象和函数式范式之间的差距
2. 借助apply()方法, Scala中的函数可以被看做是对象
3. apply方法类似于Python中的_call_, 它允许您将给定类的实例用作函数

没看懂? 请仔细看下面的一段话, 并认真体会下面的代码!

  1. apply缩短了面向对象和函数式范式之间的差距
  2. 当我们将对象以函数的方式进行调用时,Scala会隐式地将函数调用转换为在该伴生对象中调用apply()方法, 什么是函数调用?f(n)!
    如 Person(“xiaoming”) 等同于 Person.apply(“xiaoming”) , 请仔细看下面的代码
  3. 所以我们经常在伴生对象中使用 apply方法作为创建类实例的工厂方法
object Person{def main(args: Array[String]): Unit = {Person("xiaomign")  // 等同于 Person p = new Person("xiaoming"), 实例化Person类并传入name参数}def apply(name: String): Unit = {//在这里实例化对象了, 所以此时apply可以作为提供了Person类的实例对象的工厂方法Person p = new Person(name)}class Person(){//辅构造器//带参构造器//辅构造器一定要直接或间接的调用主构造器var name: String = _this(_name: String){this()this.name = _name}}
}

[案例一,]

package traitdemoclass MyAdder(x: Int) {def apply(y: Int) = x + y
}object MyAdder{def main(args: Array[String]): Unit = {val adder = new MyAdder(2)val res = adder(4) // equivalent toprintln(s"res = ${res}") //6println(adder.apply(4)) //也是6}
}

[案例二, apply 在创建对象时的应用]

  1. 通过伴生对象的apply() 方法, 实现不使用new方法创建对象, 可以对外隐藏构造方法的调用;
  2. apply() 可以重载;
  3. Scala中 obj(arg)的语句实际是在调用该对象的apply方法, 即 obj.apply(arg), 用以统一面向对象编程和函数式编程的风格;
  4. 使用new 关键字构建对象时, 调用的其实是类的构造方法, 当使用类名构建对象时, 调用的其实是伴生对象的apply()方法;
  5. 类名构建对象: new Person() 等价于 Person()
object Test {def main(args: Array[String]): Unit = {//(1)通过伴生对象的 apply 方法,实现不使用 new 关键字创建对象。val p1 = Person()println("p1.name=" + p1.name)val p2 = Person("bobo")println("p2.name=" + p2.name)}
}
//(2)如果想让主构造器变成私有的,可以在()之前加上 private
class Person private(cName: String) {var name: String = cName
}object Person {def apply(): Person = {println("apply 空参被调用")new Person("xx")}
def apply(name: String): Person = {println("apply 有参被调用")new Person(name)
}
}

4.2 特质(Trait)

  • Scala中, 利用trait(特质)类代替接口的概念, 也就是说, 当**多个类具有相同的特质(特征)**时, 就可以将这个特质(特征独立出来), 采用关键字trait声明;
  • Scla中的trait中既可以有抽象属性和方法, 也可以有具体的属性和方法, 一个类可以混入(mix in)多个特质;
  • Scala引入trait特征值,
    • 第一可以替代java的接口,
    • 第二也是对单继承机制的一种补充;

4.2.1 特质的声明

[基本语法]

trait 特质名{trait 主体
}

[案例实操]

trait PersonTrait{//声明属性var name: String = _//声明方法:def eat(): Unit = {方法体}//抽象属性var age: Int//抽象方法(省略方法体)def say(): Unit
}

4.2.2 特质基本语法

  • 一个类具有某种特质(特征), 就意味着这个类满足了这个特质(特征)的所有要素,
  • 所以在使用时, 也采用了 extends关键字
  • 如果有多个特质或存在父类, 那么需要采用 with关键字连接

[基本语法]

//1. 没有父类
class 类名 extends 特质1 with 特质2 whit 特质3 ...//2. 有父类
class 类名 extends 父类 with 特质1 with 特质2 with 特质3 ...

trait PersonTrait {//(1)特质可以同时拥有抽象方法和具体方法// 声明属性var name: String = _// 抽象属性ar age: Int// 声明方法def eat(): Unit = {println("eat")}// 抽象方法def say(): Unit
}trait SexTrait {var sex: String
}//(2)一个类可以实现/继承多个特质
//(3)所有的 Java 接口都可以当做 Scala 特质使用
class Teacher extends PersonTrait with java.io.Serializable {override def say(): Unit = {println("say")}override var age: Int = _
}object TestTrait {def main(args: Array[String]): Unit = {val teacher = new Teacherteacher.say()teacher.eat()//(4)动态混入:可灵活的扩展类的功能val t2 = new Teacher with SexTrait {override var sex: String = "男"}//调用混入 trait 的属性println(t2.sex)}
}

4.2.3 特质叠加

  • 由于一个类可以混入(mixin)多个trait, 且trait中可以有具体的属性和方法,若混入的特质中具有下同的方法(方法名,参数列表,返回值均相同), 必然会发生继承冲突问题
  • 冲突分为两种

[特质冲突-普通冲突]

  • 一个混入了多个特质, 如果这多个特质中有相同的方法(同名同参通返回), 但是这多个特质之间没有任何关系, 那么直接在中override 相同的方法即可

[特制叠加-钻石叠加问题]

  • 一个类(sub)混入了两个特质(TraitA, TraitB), 特质A和特质B具有相同的具体方法m1, 并且这两个特质均继承自相同的特质(TraitC),
  • 在类(Sub)中如何调用m1方法, 就是所谓的"钻石问题",
  • 解决钻石叠加问题, 只需要记住: 特质声明的顺序是从左到右, 而方法执行的顺序是从右向左
package traitconflictdemoobject DemonTest {def main(args: Array[String]): Unit = {val ball = new MyBallball.descri()println("======================================")//动态混入val ball2 = new MyNewBall with Category with Color {override def descri(): String = {" my ball is a new " + super.descri()}}ball2.descri()}case class MyNewBall()
}//钻石叠加问题: sub 混入特质A,B, 特质A.B具有相同的方法, 特质AB均继承了特质C,  特质方法调用从左向右 (a->b->c)
//            c(ball)
//     b(color)    a(category)
//          sub(myBall)
trait Ball{var ball: String = "ball"def descri(): String = ball
}trait Color extends Ball{var color: String = "red"override def descri(): String = color + super.descri()
}trait Category extends Ball{var category: String = "basket"override def descri(): String = category + super.descri()
}class MyBall extends Category with Color{override def descri(): String = {"my ball is a " + super.descri()}
}

super并不是指继承关系,而是指的加载顺序,从右到左,不一定调用父类的,而是调用左边的混入特质,左边没有了,才调用父类的
抽象类混入特质,从右往左调用,super调用的是当前特质左边的特质,如果没有特质了,才调用父类的,而不是直接调用父类的方法,如果想直接调用父类的,可以加泛型限制,

4.2.4 特质叠加执行顺序

4.2.5 特质和抽象类的区别

  1. 优先使用特质; 一个类扩展多个特质是很方便的, 但是只能扩展一个抽象类;
  2. 如果你需要构造函数参数, 使用抽象类, 因为抽象类可以定义带参数的构造函数, 而特质不行(无论是有参还是无参的构造)

4.2.6 特质自身类型

四, Scala 伴生对象, 特质相关推荐

  1. 学习Scala:伴生对象和伴生类之间的关系(二)

    孤立对象是只有一个object关键字修饰的对象,该对象会编译成两个class文件,一个是以孤立对象的名字命名的class, 一个是以孤立对象的名字后面加上一个$ 字符命名的class, 这个class ...

  2. scala 伴生对象的作用

    1.什么是伴生对象 scala中的类不能定义静态成员,而代之以定义单例对象来替代 单例对象通过object关键字来声明 单例对象中的所有方法,可以直接通过object单例对象的名字直接来调用. 一个单 ...

  3. Scala中Object和Class区别(伴生类和伴生对象)

    文章目录 一,介绍 二,类Class 2.1 类定义 2.2 构造器 1.基本语法 2.构造器参数 2.3 私有成员和Getter/Setter语法 三,单例对象Object 四,伴生对象和伴生类介绍 ...

  4. Scala类的定义,主/辅构造器,以及方法中的变量定义,单例对象,伴生对象,Apply方法调用,应用程序对象

    1. 类 1.1. 类的定义 package cn.toto.scala.day2/*** 在Scala中,类并不用声明为public类型的.* Scala源文件中可以包含多个类,所有这些类都具有共有 ...

  5. Scala学习视频心得(一)语言特点、伴生对象

    文章目录 1.Scala语言特点 2.伴生对象 1.Scala语言特点 ​ Scala是一门以Java虚拟机(JVM)为运行环境并将面向对象和函数式编程的最佳特性结合在一起的静态类型编程语言(静态语言 ...

  6. [Scala基础]-- 伴生类和伴生对象

    Scala比 Java 更面向对象的一个方面是 Scala 没有静态成员.替代品是,Scala 有: 单例对象:singleton object. 除了用 object 关键字替换了 class 关键 ...

  7. 大数据开发语言Scala(三)——伴生类和伴生对象

    Scala语言是完全面向对象的语言,所以并没有静态的操作(即在Scala中没有静态的概念).但是为了能够和Java语言交互(因为Java中有静态概念),就产生了一种特殊的对象来模拟类对象,该对象为单例 ...

  8. 每天学一点Scala之 伴生类和伴生对象

    1.  object 相当于class的单个实例,因此,在object里声明的变量都是静态变量,静态方法 2.  在object里声明的变量,都是全局变量,也就是类的公共属性,或者类似于java中父类 ...

  9. Scala单例对象(伴生对象)

    概念 Scala语言是完全面向对象的语言,所以并没有静态的操作(即在Scala中没有静态的概 念).但是为了能够和Java语言交互(因为Java中有静态概念),就产生了一种特殊的对象 来模拟类对象,该 ...

最新文章

  1. 2021年大数据Kafka(七):Kafka的分片和副本机制
  2. Tensorflow CIFAR-10训练例子报错解决
  3. ESXI开启snmp协议方法
  4. 一文搞懂 SQL:基础知识和业务实践总结
  5. BitMap位图与海量数据的理解与应用
  6. Cube Or 北方大学生训练赛
  7. python和php合成,Python照片合成的方法详解
  8. Debian下面修改Grub2的默认启动顺序
  9. Eclipse安装Alibaba Cloud Toolkit并连接阿里云云数据库
  10. 抽象类java启动线程_java 线程复习笔记
  11. TCP/IP网络编程(2)
  12. Delphi之TStrings和TStringLists类【转】
  13. 网络原理制作bt采集蜘蛛
  14. OneNote同步问题,提示没有权限
  15. Rockchip | Rockchip Kernel的获取与构建
  16. 记录——python与华为云对象存储服务OBS
  17. 利用ECharts可视化mysql数据库中的数据
  18. 网络OSI(七层模型)
  19. TokenInsight 对话首席——钱包安全与发展
  20. 《操作系统真象还原》第五章 ---- 轻取物理内存容量 启用分页畅游虚拟空间 力斧直斩内核先劈一角 闲庭信步摸谈特权级

热门文章

  1. 博客图片html代码,【html博客代码】图片羽化代码
  2. CSS开发中所有基本属性的使用技巧
  3. ei论文计算机,容易写的计算机ei论文题目 计算机ei专业论文题目如何拟
  4. [置顶] 【游戏产业的5年之变】
  5. 飞桨 DNN波士顿房价预测
  6. 交换机ftp将文件传到服务器,如何用FTP实现交换机间配置文件复制?
  7. laravel过滤富文本提交的标签(防止XSS等js脚本攻击)
  8. 《惢客创业日记》2019.04.25(周四)如何解决骚扰电话?
  9. RocketMQ重试机制(ACK确认机制)
  10. 新电脑如何分盘---傻瓜式教学