Scala系列15:抽象,匿名内部类,特质,模板等使用详解与演示

2020-09-28 19:41发布

目录

0. 抽象类

0.1 定义

0.2代码演示

1.抽象字段

2.匿名内部类

2.1定义

2.2示例

3.特质的使用

3.1特质的定义

3.1.1定义特质

3.1.2 特质继承

3.1.3特质使用演示

3.2特质 | 定义具体的方法

3.3 trait中定义具体的字段和抽象的字段

3.3.1 定义

3.3.2 示例说明

3.3 使用trait实现模板模式

3.3.1示例

3.4 对象混入trait

3.4.1定义

3.4.2示例

3.5 trait的构造机制

3.51 定义

3.5.2 示例说明

3.6 trait继承class

3.6.1示例


0. 抽象类

和Java语言一样,scala中也可以定义抽象类

0.1 定义

如果类的某个成员在当前类中的定义是不包含完整的,它就是一个抽象类

不完整定义有两种情况:

  1. 方法没有方法体(抽象方法

  2. 变量没有初始化(抽象字段

定义抽象类和Java一样,在类前面加上abstract关键字

  1. // 定义抽象类

  2. abstract class 抽象类名 {

  3. // 定义抽象字段

  4. val 抽象字段名:类型

  5. // 定义抽象方法

  6. def 方法名(参数:参数类型,参数:参数类型...):返回类型

  7. }

0.2代码演示

  1. package com.robot.scalademo1

  2. class Person3

  3. class Student3 extends Person3

  4. object _08ObjectDemo {

  5. // 创建形状抽象类

  6. abstract class Shape {

  7. def area:Double

  8. }


  9. // 创建正方形类

  10. class Square(var edge:Double /*边长*/) extends Shape {

  11. // 实现父类计算面积的方法

  12. override def area: Double = edge * edge

  13. }


  14. // 创建长方形类

  15. class Rectangle(var length:Double /*长*/, var width:Double /*宽*/) extends Shape {

  16. override def area: Double = length * width

  17. }


  18. // 创建圆形类

  19. class Cirle(var radius:Double /*半径*/) extends Shape {

  20. override def area: Double = Math.PI * radius * radius

  21. }



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

  23. val s1:Shape = new Square(2)

  24. val s2:Shape = new Rectangle(2,3)

  25. val s3:Shape = new Cirle(2)


  26. println(s1.area)

  27. println(s2.area)

  28. println(s3.area)

  29. }

  30. }


  31. /**

  32. * 4.0

  33. 6.0

  34. 12.566370614359172

  35. */

1.抽象字段

在scala中,也可以定义抽象的字段。如果一个成员变量是没有初始化,我们就认为它是抽象的。

语法

  1. abstract class 抽象类 {

  2. val/var 抽象字段:类型

  3. }

示例说明

  1. 创建一个Person抽象类,它有一个String抽象字段WHO_AM_I

  2. 创建一个Student类,继承自Person类,重写WHO_AM_I字段,初始化为学生

  3. 创建一个Policeman类,继承自Person类,重写WHO_AM_I字段,初始化警察

  4. 添加main方法,分别创建Student/Policeman的实例,然后分别打印WHO_AM_I

  5. // 定义一个人的抽象类

  6. package com.robot.scalademo1


  7. abstract class Person6 {

  8. // 没有初始化的val字段就是抽象字段

  9. val WHO_AM_I:String

  10. }

  11. class Student6 extends Person6 {

  12. override val WHO_AM_I: String = "学生"

  13. }


  14. class Policeman6 extends Person6 {

  15. override val WHO_AM_I: String = "警察"

  16. }

  17. object _08ObjectDemo {


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

  19. val p1 = new Student6

  20. val p2 = new Policeman6


  21. println(p1.WHO_AM_I) //学生

  22. println(p2.WHO_AM_I) //警察


  23. }

  24. }

2.匿名内部类

  1. 匿名内部类是没有名称的子类,直接用来创建实例对象。Spark的源代码中有大量使用到匿名内部类。

  2. scala中的匿名内部类使用与Java一致。

2.1定义

  1. val/var 变量名 = new 类/抽象类 {

  2. // 重写方法

  3. }

Copy

2.2示例

示例说明

  1. 创建一个Person抽象类,并添加一个sayHello抽象方法

  2. 添加main方法,通过创建匿名内部类的方式来实现Person

  3. 调用匿名内部类对象的sayHello方法

参考代码

  1. abstract class Person7 {

  2. def sayHello:Unit

  3. }


  4. object Main7 {

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

  6. // 直接用new来创建一个匿名内部类对象

  7. val p1 = new Person7 {

  8. override def sayHello: Unit = println("我是一个匿名内部类")

  9. }

  10. p1.sayHello

  11. }

  12. }

3.特质的使用

scala中没有Java中的接口(interface),替代的概念是——特质。用法跟Java中几乎一样。

3.1特质的定义

  • 特质是scala中代码复用的基础单元

  • 它可以将方法和字段定义封装起来,然后添加到类中

  • 与类继承不一样的是,类继承要求每个类都只能继承一个超类,而一个类可以添加任意数量的特质。

  • 特质的定义和抽象类的定义很像,但它是使用trait关键字

3.1.1定义特质

  1. trait 名称 {

  2. // 抽象字段

  3. // 抽象方法

  4. }

3.1.2 特质继承

  1. class 类 extends 特质1 with 特质2 {

  2. // 字段实现

  3. // 方法实现

  4. }

  • 使用extends来继承trait(scala不论是类还是特质,都是使用extends关键字)

  • 如果要继承多个trait,则使用with关键字

  • 注意不仅类可以继承trait,单例object也可以继承trait,trait也可以继承trait.

3.1.3特质使用演示

1.类单继承特质的使用

  1. /**

  2. 创建一个Logger特质,添加一个接受一个String类型参数的log抽象方法

  3. 创建一个ConsoleLogger类,继承Logger特质,实现log方法,打印消息

  4. 添加main方法,创建ConsoleLogger对象,调用log方法

  5. *

  6. */

  7. trait Logger {

  8. // 抽象方法

  9. def log(message:String)

  10. }


  11. class ConsoleLogger extends Logger {

  12. override def log(message: String): Unit = println("控制台日志:" + message)

  13. }


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

  15. val logger = new ConsoleLogger

  16. logger.log("这是一条日志")

  17. }

2.类多继承特质的使用

  1. /**

  2. 创建一个MessageSender特质,添加send方法

  3. 创建一个MessageReceiver特质,添加receive方法

  4. 创建一个MessageWorker实现这两个特质

  5. 在main中调用,分别调用send方法、receive方法

  6. **/


  7. trait MessageSender {

  8. def send(msg:String)

  9. }


  10. trait MessageReceive {

  11. def receive():String

  12. }


  13. class MessageWorker extends MessageSender with MessageReceive {

  14. override def send(msg: String): Unit = println(s"发送消息:${msg}")


  15. override def receive(): String = "你好!我叫一个好人!"

  16. }


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

  18. val worker = new MessageWorker

  19. worker.send("hello")

  20. println(worker.receive())

  21. }

3.单例objectg继承trait

  1. /**


  2. 创建一个Logger特质,添加一个log抽象方法

  3. 创建一个ConsoleLogger的object,实现LoggerForObject特质,实现log方法,打印消息

  4. 编写main方法,调用ConsoleLogger的log方法

  5. **/


  6. trait Logger {

  7. def log(message:String)

  8. }


  9. object ConsoleLogger extends Logger {

  10. override def log(message: String): Unit = println("控制台消息:" + message)

  11. }


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

  13. ConsoleLogger.log("程序退出!")

  14. }

4.特质trait继承trait的使用

  1. trait Logger {

  2. println("执行Logger构造器")

  3. }


  4. trait MyLogger extends Logger {

  5. println("执行MyLogger构造器")

  6. }


  7. trait TimeLogger extends Logger {

  8. println("执行TimeLogger构造器")

  9. }


  10. class Person{

  11. println("执行Person构造器")

  12. }


  13. class Student extends Person with TimeLogger with MyLogger {

  14. println("执行Student构造器")

  15. }


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

  17. new Student

  18. }


  19. // 程序运行输出如下:

  20. // 执行Person构造器

  21. // 执行Logger构造器

  22. // 执行TimeLogger构造器

  23. // 执行MyLogger构造器

  24. // 执行Student构造器

3.2特质 | 定义具体的方法

和类一样,trait中还可以定义具体的方法

示例说明

  1. 定义一个Logger特质,添加log实现方法

  2. 定义一个UserService类,实现Logger特质

    • 添加add方法,打印"添加用户"

  3. 添加main方法

    • 创建UserService对象实例

    • 调用add方法

参考代码

  1. trait LoggerDetail {

  2. // 在trait中定义具体方法

  3. def log(msg:String) = println(msg)

  4. }


  5. class UserService extends LoggerDetail {

  6. def add() = log("添加用户")

  7. }


  8. object MethodInTrait {

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

  10. val userService = new UserService

  11. userService.add()

  12. }

  13. }

3.3 trait中定义具体的字段和抽象的字段

3.3.1 定义

  • 在trait中可以定义具体字段和抽象字段

  • 继承trait的子类自动拥有trait中定义的字段

  • 字段直接被添加到子类中

3.3.2 示例说明

通过trait来实现一个日志输出工具,该日志工具可以自动添加日志的日期

步骤

  1. 创建Logger特质

    • 定义一个SimpleDateFormat字段,用来格式化日期(显示到时间)

    • 定义一个TYPE抽象字段,用于定义输出的信息

    • 创建一个log抽象方法,用于输出日志

  2. 创建ConsoleLogger类,实现TYPE抽象字段和log方法

  3. 添加main方法

    • 创建ConsoleLogger类对象

    • 调用log方法

参考代码

  1. trait Logger {

  2. val sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm")

  3. def log(msg:String)

  4. }


  5. class ConsoleLogger extends Logger {

  6. override def log(msg: String): Unit = {

  7. val info = s"${sdf.format(new Date())}:控制台消息:${msg}"

  8. println(info)

  9. }

  10. }


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

  12. val logger = new ConsoleLogger()

  13. logger.log("NullPointerException")

  14. }

3.3 使用trait实现模板模式

在scala中,trait是可以定义抽象方法,也可以定义具体方法的

  • trait中定义了一个抽象方法

  • trait中定义了其他的几个具体方法,会调用抽象方法

  • 其他实现类可以来实现抽象方法

  • 真正调用trait中具体方法的时候,其实会调用实现类的抽象方法实现

3.3.1示例

示例说明

  • 编写一个日志输出工具,分别有info、warn、error三个级别的日志输出

  • 日志输出的方式要求设计为可扩展的,例如:可以输出到控制台、将来也可以扩展输出到文件、数据库等

实现步骤

  1. 添加一个Logger特质

    • 添加一个log抽象方法

    • 添加一个info、warn、error具体方法,这几个方法调用log抽象方法

  2. 创建ConsoleLogger类,实现Logger特质

  3. 添加main方法

    • 创建ConsoleLogger类对象

    • 分别调用info、warn、error方法输出日志

参考代码

  1. package com.robot.scalademo1

  2. trait Logger {

  3. def log(msg:String)

  4. def info(msg:String) = log("INFO:" + msg)

  5. def warn(msg:String) = log("WARN:" + msg)

  6. def error(msg:String) = log("ERROR:" + msg)

  7. }


  8. class ConsoleLogger extends Logger {

  9. override def log(msg: String): Unit = {

  10. println(msg)

  11. }

  12. }


  13. object _08ObjectDemo {


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

  15. val logger = new ConsoleLogger

  16. logger.info("信息日志")

  17. logger.warn("警告日志")

  18. logger.error("错误日志")

  19. }

  20. }/**

  21. INFO:信息日志

  22. WARN:警告日志

  23. ERROR:错误日志


  24. */

3.4 对象混入trait

scala中可以将trait混入到对象中,就是将trait中定义的方法、字段添加到一个对象中

3.4.1定义

val/var 对象名 = new 类 with 特质

3.4.2示例

  • 给一个对象添加一些额外的行为

步骤

  1. 创建一个Logger特质

    • 添加一个log实现方法,打印参数

  2. 创建一个UserService类

  3. 添加main方法

    • 创建UserService对象,混入Logger特质

    • 调用log方法

参考代码

  1. trait Logger {

  2. def log(msg:String) = println(msg)

  3. }


  4. class UserService


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

  6. val service = new UserService with Logger

  7. service.log("混入的方法")

  8. }

3.5 trait的构造机制

如果一个类实现了多个trait,那这些trait是如何构造的呢?

3.51 定义

  • trait也有构造代码,但和类不一样,特质不能有构造器参数

  • 每个特质只有一个无参数的构造器。

  • 一个类继承另一个类、以及多个trait,当创建该类的实例时,它的构造顺序如下:

    1. 执行父类的构造器

    2. 从左到右依次执行trait的构造器

    3. 如果trait有父trait,先构造父trait,如果多个trait有同样的父trait,则只初始化一次

    4. 执行子类构造器

3.5.2 示例说明

  • 定义多个特质,然后用一个类去实现它们

  • 测试trait的构造顺序

步骤

  1. 创建一个Logger特质,在构造器中打印"执行Logger构造器!"

  2. 创建一个MyLogger特质,继承自Logger特质,,在构造器中打印"执行MyLogger构造器!"

  3. 创建一个TimeLogger特质,继承自Logger特质,在构造器中打印"执行TimeLogger构造器!"

  4. 创建一个Person类,在构造器中打印"执行Person构造器!"

  5. 创建一个Student类,继承自Person、MyLogger、TimeLogge特质,在构造器中打印"执行Student构造器!"

  6. 添加main方法,实例化Student_One类,观察输出。

参考代码

  1. trait Logger {

  2. println("执行Logger构造器")

  3. }


  4. trait MyLogger extends Logger {

  5. println("执行MyLogger构造器")

  6. }


  7. trait TimeLogger extends Logger {

  8. println("执行TimeLogger构造器")

  9. }


  10. class Person{

  11. println("执行Person构造器")

  12. }


  13. class Student extends Person with TimeLogger with MyLogger {

  14. println("执行Student构造器")

  15. }


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

  17. new Student

  18. }


  19. // 程序运行输出如下:

  20. // 执行Person构造器

  21. // 执行Logger构造器

  22. // 执行TimeLogger构造器

  23. // 执行MyLogger构造器

  24. // 执行Student构造器

3.6 trait继承class

trait也可以继承class的。特质会将class中的成员都继承下来。注意这一点很特别。

3.6.1示例

示例说明

  • 定义一个特质,继承自一个class

步骤

  1. 创建一个MyUtils类,定义printMsg方法

  2. 创建一个Logger特质,继承自MyUtils,定义log方法

  3. 创建一个Person类,添加name字段

    • 继承Logger特质

    • 实现sayHello方法,调用log方法

  4. 添加main方法,创建一个Person对象,调用sayHello方法

参考代码

  1. package com.robot.scalademo1

  2. class MyUtil {

  3. def printMsg(msg:String) = println(msg)

  4. }


  5. trait Logger extends MyUtil {

  6. def log(msg:String) = printMsg("Logger:" + msg)

  7. }


  8. class Person extends Logger {

  9. def sayHello() = log("你好")

  10. }


  11. object _08ObjectDemo {


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

  13. val person = new Person

  14. person.sayHello()

  15. }


  16. }/**

  17. Logger:你好

  18. */

作者:涤生手记

链接:https://blog.csdn.net/qq_26442553/article/details/108410979

来源:CSDN
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。