大数据技术之_16_Scala学习_06
第八章 面向对象编程-高级
8.1 静态属性和静态方法
8.1.1 静态属性-提出问题
8.1.2 基本介绍
8.1.3 伴生对象的快速入门
示例代码如下:
package com.atguigu.chapter08.test
object AccompanyObjectDemo {
def main(args: Array[String]): Unit = {
println(ScalaPerson.sex) // 在底层等价于 ScalaPerson$.MPDULE$.sex()
ScalaPerson.sayHi() // 在底层等价于 ScalaPerson$.MPDULE$.sayHi()
}
}
// class ScalaPerson 是伴生类,将非静态的内容写到该类中
// class ScalaPerson 编译后生成 ScalaPerson.class
class ScalaPerson {
var name: String = _
}
// object ScalaPerson 是伴生对象,将静态的内容写到该对象中
// object ScalaPerson 编译后生成 ScalaPerson$.class
// 对于伴生对象的内容,我们可以直接通过 ScalaPerson.属性 或者 ScalaPerson.方法
object ScalaPerson {
var sex: Boolean = true
def sayHi():Unit = {
println("object ScalaPerson sayHi")
}
}
输出结果如下:
true
object ScalaPerson sayHi
伴生对象的快速入门源码分析图解
8.1.4 伴生对象的小结
8.1.5 最佳实践-使用伴生对象解决小孩游戏问题
设计一个 var total Int 表示总人数,我们在创建一个小孩时,就把 total 加1,并且 total 是所有对象共享的就 ok 了。我们使用伴生对象来解决。
示例代码如下:
package com.atguigu.chapter08.test
object ChildGameTest {
def main(args: Array[String]): Unit = {
// 传统的方式
// 创建很多小孩,加入游戏
// 定义一个变量 total
// var total = 0
// 我们这个 total 没有在一个对象里面,不是面向对象的编程
// 伴生对象的方式
val child01 = new Child("白骨精")
val child02 = new Child("银角大王")
val child03 = new Child("牛魔王")
Child.joinGame(child01)
Child.joinGame(child02)
Child.joinGame(child03)
Child.showNum()
}
}
// 伴生类
class Child(cName: String) {
var name = cName
}
// 伴生对象
object Child {
// 总人数
var total: Int = 0
def joinGame(child: Child): Unit = {
printf("%s 小朋友加入游戏\n", child.name)
total += 1
}
def showNum(): Unit = {
printf("当前有 %d 个小朋友在玩游戏\n", total)
}
}
输出结果如下:
白骨精 小朋友加入游戏
银角大王 小朋友加入游戏
牛魔王 小朋友加入游戏
当前有 3 个小朋友在玩游戏
8.1.6 伴生对象-apply 方法
在伴生对象中定义 apply 方法,可以实现: 类名(参数)
方式 来创建对象实例。
示例代码如下:
package com.atguigu.chapter08.apply
object ApplayDemo01 {
def main(args: Array[String]): Unit = {
val list = List(1, 2, 3)
println(list) // List(1, 2, 3)
// 传统的方式:new 出来
val p1 = new Pig("小花猪")
println("p1.name=" + p1.name)
// 现在的方式
// 在伴生对象中自定义 apply 方法,可以实现: 类名(参数) 方式 来创建对象实例。
// 使用 apply 方法来创建对象
val p2 = Pig("小黑猪") // 自动触发 apply(pName: String)
val p3 = Pig() // 自动触发 apply()
println("p2.name=" + p2.name)
println("p3.name=" + p3.name)
}
}
// 伴生类
class Pig(pName: String) {
var name: String = pName
}
// 伴生对象
object Pig {
// 编写自定义的 apply 方法
def apply(pName: String): Pig = new Pig(pName)
def apply(): Pig = new Pig("默认同名猪猪")
}
输出结果如下:
List(1, 2, 3)
p1.name=小花猪
p2.name=小黑猪
p3.name=默认同名猪猪
8.2 单列对象
这个部分我们放在【第十七章 scala 设计模式】专题进行讲解。
8.3 接口
8.3.1 回顾 Java 接口
8.3.2 Scala 接口的介绍
trait 原理示意图如下:
8.3.3 trait 的声明
示例代码如下:
package com.atguigu.chapter08.mytrait
object TraitDemo01 {
def main(args: Array[String]): Unit = {
}
}
// 在 scala 中,java 中的所有接口可以当做特质使用。
// Serializable:就是 scala 的一个特质。
// trait Serializable extends Any with java.io.Serializable
object T1 extends Serializable {
}
// Cloneable:就是 scala 的一个特质。
// trait Cloneable extends java.lang.Cloneable
object T2 extends Cloneable {
}
8.3.4 Scala 中 trait 的使用
8.4 特质 trait
8.4.1 特质的快速入门案例分析
8.4.2 代码完成
示例代码如下:
package com.atguigu.chapter08.mytrait
object TraitDemo02 {
def main(args: Array[String]): Unit = {
val c1 = new C()
val e1 = new E()
c1.getConnect()
e1.getConnect()
println("----------")
c1.getConnect("张三", "123456")
e1.getConnect("李四", "000000")
}
}
// 按照要求定义一个 trait
trait trait02 {
// 定义一个规范
// 声明方法,抽象的
def getConnect()
def getConnect(user: String, pwd: String): Unit
}
class A {
}
class B extends A {
}
class C extends A with trait02 {
override def getConnect(): Unit = {
println("c 连接mysql")
}
override def getConnect(user: String, pwd: String): Unit = {
println(user +" 用户连接mysql")
}
}
class D {
}
class E extends D with trait02 {
override def getConnect(): Unit = {
println("e 连接oracle")
}
def getConnect(user: String, pwd: String): Unit = {
println(user +" 用户连接oracle")
}
}
class F extends D {
}
输出结果如下:
c 连接mysql
e 连接oracle
----------
张三 用户连接mysql
李四 用户连接oracle
8.4.3 特质 trait 的再说明
1、Scala 提供了特质(trait),特质可以同时拥有抽象方法和具体方法,一个类可以实现/继承多个特质。
2、特质中没有实现的方法就是抽象方法。类通过 extends 继承特质,通过 with 可以继承多个特质。
3、所有的 java 接口都可以当做 Scala 特质使用。
示例代码如下:
package com.atguigu.chapter08.mytrait
object TraitDemo03 {
def main(args: Array[String]): Unit = {
val s1 = new Sheep
s1.sayHi()
s1.sayHello()
}
}
// 当一个 trait 有抽象方法和非抽象方法时:
// 那么一个 trait 在底层就对应生成两个东东:
// 1、Trait03.class 接口 Trait03
// 2、Trait03$class.class 抽象类 Trait03$class
trait Trait03 {
// 定义规范
// 抽象方法
def sayHi()
// 实现普通方法
def sayHello(): Unit = {
println("say hello")
}
}
// 当一个 trait 有 接口 和 抽象类 时:
// class Sheep extends Trait03 在底层对应:
// 1、class Sheep implements Trait03
// 2、当在 Sheep 类中要使用 Trait03 中已实现的方法,就通过 Trait03$class.sayHello()
class Sheep extends Trait03 {
override def sayHi(): Unit = {
println("say hi")
}
}
输出结果如下:
say hi
say hello
示例代码的底层源码分析图解:
演示一个类继承多个特质的语法:
8.4.4 带有具体实现的特质
说明:和 Java 中的接口不太一样的是特质中的方法并不一定是抽象的,也可以有非抽象方法(即:实现了的方法)。实现了的方法的术语: 默认实现。提示:在 jdk1.8 中接口也可以有默认实现,就是 scala 的 trait 的带来的特性。
示例代码如下:
package com.atguigu.chapter08.mytrait
/**
* 带有具体实现的特质
* 说明:和 Java 中的接口不太一样的是特质中的方法并不一定是抽象的,也可以有非抽象方法(即:实现了的方法)。实现了的方法的术语: 默认实现。
* 提示:在 jdk1.8 中接口也可以有默认实现,就是 scala 的 trait 的带来的特性。
*/
object TraitDemo04 {
def main(args: Array[String]): Unit = {
val mysql = new MySQL0
mysql.insert(2)
}
}
trait Operate0 {
def insert(id: Int): Unit = {
println("保存数据=" + id)
}
}
trait DB0 extends Operate0 {
override def insert(id: Int): Unit = {
print("向数据库中")
super.insert(id)
}
}
class MySQL0 extends DB0 {
}
输出结果如下:
向数据库中保存数据=2
8.4.5 带有特质的对象:动态混入(mixin)
示例代码如下:
package com.atguigu.chapter08.mixin
/**
* 1、除了可以在类声明时继承特质以外,还可以在构建对象时混入特质,扩展目标类的功能。
* 2、此种方式也可以应用于对抽象类功能进行扩展。
* 3、动态混入是 Scala 特有的方式(java 没有动态混入),可在不修改类声明/定义的情况下,扩展类的功能,非常的灵活,耦合性低 。
*/
object MixinDemo01 {
def main(args: Array[String]): Unit = {
// 在不修改类的定义的基础上,让该类可以使用 trait 中的方法
val oracle = new OracleDB1 with Operate1 // 动态混入
oracle.insert(999)
val mysql = new MySQL1 with Operate1
mysql.insert(400)
// 如果抽象类中有抽象的方法,如何动态混入特质?如下:
val mysql11 = new MySQL11 with Operate1 {
override def say(