Scala笔记(二)面向对象

本文详细讲解了Scala中的类与对象,包括主构造器、辅助构造器、单例对象、App Trait、伴生对象、访问权限、apply方法、override和super,以及特质(trait)的使用、模板模式和调用链模式。深入理解这些概念有助于提升Scala编程效率。
摘要由CSDN通过智能技术生成

一、类和对象

主构造器

// 语法:
// class 类名(var/val 参数名:类型 = 默认值, var/val 参数名:类型 = 默认值) {
	// 构造代码块
// }

// 使用
class Person(var name:String = "", var age:Int = 0) {
    println("调用主构造器")
}
def main(args: Array[String]): Unit = {
    val zhangsan = new Person("张三", 20)
    println(zhangsan.name)
    println(zhangsan.age)

    val empty = new Person
    println(empty.name)
    println(empty.age)

    val man40 = new Person(age = 40)
    println(man40.name)
    println(man40.age)
}
  • 主构造器的参数列表是直接定义在类后面,添加了 val/var 表示直接通过主构造器定义成员变量
  • 构造器参数列表可以指定默认值
  • 创建实例,调用构造器可以指定字段进行初始化
  • 整个 class 中除了字段定义和方法定义的代码都是构造代码

辅助构造器

// 语法:
// def this(参数名:类型, 参数名:类型) {
	// 第一行需要调用主构造器获取其他构造器
	// 构造器代码
// }

// 使用
// 定义主构造器
class Customer(var name:String = "", var address:String = "") {
	// 定义辅助构造器
	def this(data:Array[String]) {
	 	this(data(0), data(1))
	}
}
def main(args: Array[String]): Unit = {
	// 使用辅助构造器创建对象
	val customer = new Customer(Array("张三", "北京"))
	
	println(customer.name)
	println(customer.address)
}

辅助构造器的第一行代码,必须要调用主构造器或者其他辅助构造器

单例对象

Scala 中没有 Java 中的静态成员,我们想要定义类似于 Java 的 static 变量、static 方法,就是使用到 scala 中的单例对象——object。
单例对象表示全局仅有一个对象(类似于 Java static 概念)

  • 定义单例对象和定义类很像,就是把 class 换成 object
  • 在 object 中定义的成员变量类似于 Java 的静态变量
  • 可以使用 object 直接引用成员变量
// 创建单例对象
object Dog {
	// 定义了一个单例对象的成员
	// 类似于Java中static变量
	val LEG_NUM = 4
	
	// 定义成员方法
	def eat() = {
		println("狗吃肉")
	}
}
// 访问单例对象中的成员变量和成员方法
def main(args: Array[String]): Unit = {
	println(Dog.LEG_NUM)
	Dog.eat
}

实现 App Trait 来定义入口

// 语法:
// object 单例对象名 extends App {
	// 方法体
// }

// 使用:
object Demo extends App {
  println("hello")
}

伴生对象

一个 class 和 object 具有同样的名字。这个 object 称为伴生对象,这个 class 称为伴生类。

  • 伴生对象必须要和伴生类一样的名字
  • 伴生对象和伴生类在同一个 scala 源文件中
  • 伴生对象和伴生类可以互相访问 private 属性

private[this] 访问权限

如果某个成员的权限设置为 private[this],表示只能在当前类中访问,伴生对象也不可以访问。

classs Person(private[this] var name:String)

apply 方法

class Person(var name:String, var age:Int)

object Person {
	def main(args: Array[String]): Unit = {
		def apply(name: String, age: Int): Person = new Person(name, age)
	    // 使用类名来快速创建对象
	    val zhangsan = Person("张三", 20)
	    println(zhangsan.name)
	    println(zhangsan.age)
  }
}

override 和 super

类似于 Java 语言,我们在子类中使用 override 来重写父类的成员,可以使用 super 来引用父类。
用法:

  • 子类要覆盖父类中的一个方法,必须要使用 override 关键字
  • 使用 override 来重写一个 val 字段
  • 使用 super 关键字来访问父类的成员方法
class Person {
	val name:String = ""
	
	def getName():String = this.name
}

class Student extends Person {
	// 重写字段
	override val name:String = "student"
	
	// 重写成员方法
	override def getName(): String = "hello, " + super.getName()
}

def main(args: Array[String]): Unit = {
	val student = new Student
	println(student.name)  // student
	println(student.getName())  // hello, student
}

isInstanceOf/asInstanceOf

// 用法:
// 判断对象是否为指定类以及其子类的对象,不能精确判断出对象就是指定类的对象
// val trueOrFalse:Boolean = 对象.isInstanceOf[类型]
// 将对象转换为指定类型
// val 变量 = 对象.asInstanceOf[类型]

// 使用:
class Person

class Student extends Person

def main(args: Array[String]): Unit = {
	val student = new Student
	if(student.isInstanceOf[Student]) {
		// 是Student类型
		val student1 = student.asInstanceOf[Student]
		println(student1)
	} else {
		// 不是Student类型
		println("不是Student类型")
	}
}

getClass 和 classOf

用法:

  • 对象.getClass 可以精确获取对象的类型
  • classOf[x] 可以精确获取类型
  • 使用 == 操作符可以直接比较类型
class Person
class Student extends Person

val student: Person = new Student
student.isInstanceOf[Person]  // true
// 使用getClass获取对象的类型
// 使用classOf获取类的类型
student.getClass == classOf[Person]  // false
student.getClass == classOf[Student]  // true

样例类

样例类是一种特殊类,它可以用来快速定义一个用于保存数据的类(类似于 Java POJO 类)。

定义

// 语法:
// case class 样例类名([var/val] 成员变量名1:类型1, 成员变量名2:类型2, 成员变量名3:类型3)

// 用法:
// 1. 定义样例类,定义成员变量(默认不可变)
case class Person(var name:String, var age:Int)

def main(args: Array[String]): Unit = {
	// 2. 创建样例类对象
	val zhangsan = Person("张三", 20)
	
	zhangsan.age = 23
	
	println(zhangsan)  // Person(张三,23)
}

样例类的方法

当我们定义一个样例类,编译器自动帮助我们实现了以下几个有用的方法:

  • apply 方法
  • toString 方法
  • equals 方法
  • hashCode 方法
  • copy 方法
// copy方法:可以快速创建一个相同的实例对象,可以使用带名参数指定给成员进行重新赋值
case class Person(name:String, age:Int)
def main(args: Array[String]): Unit = {
	var lisi = Person("李四", 21)
	
	// 使用copy方法来创建一个新的对象
	val wangwu = lisi.copy(name = "王五")
	
	println(wangwu)  // Person(王五,21)
}

样例对象

使用场景:

  1. 定义枚举
  2. 作为没有任何参数的消息传递(Akka 编程会使用到)
  • 定义
    样例对象是单例的,而且它没有主构造器。
// 语法:
// case object 样例对象名

// 1. 创建一个Sex枚举(样例对象)
trait Sex
// 创建两个样例对象,从特质继承
case object Male extends Sex
case object Female extends Sex

// 2. 定义一个样例类,使用Sex枚举
case class Person(name:String, sex:Sex)

def main(args: Array[String]): Unit = {
	// 3. 创建样例类的对象
	val zhangsan = Person("张三", Male)
	val lisi = Person("李四", Female)
	
	println(zhangsan)  // Person(张三,Male)
	println(lisi)  // Person(李四,Female)
}

抽象类

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

  • 方法没有方法体(抽象方法)
  • 变量没有初始化(抽象字段)
// 定义抽象类
abstract class 抽象类名 {
	// 定义抽象字段
	val 抽象字段名:类型
	// 定义抽象方法
	def 方法名(参数:参数类型, 参数:参数类型,...): 返回类型
}

匿名内部类

// 语法:
// val/var 变量名 = new 类/抽象类 {
	// 重写方法
// }

abstract class Person {
	def sayHello()
}
def main(args: Array[String]): Unit = {
	val person = new Person {
		override def sayHello(): Unit = println("hello")
	}
	person.sayHello()
}

二、特质(trait)

Scala 中没有 Java 中的接口,替代的的概念是——特质。

  • 特质是 Scala 中代码复用的基础单元
  • 它可以将方法和字段定义封装起来,然后添加到类中
  • 与类继承不一样的是,类继承要求每个类都只能继承一个超类,而一个类可以添加任意数量的特质
  • 特质的定义和抽象类的定义很像,但它是使用 trait 关键字

作为接口使用

// 语法:
// 定义特质
// trait 名称 {
	// 抽象字段
	// 抽象方法
// }
// 继承特质
// class 类 extends 特质1 with 特质2 {
	// 字段实现
	// 方法实现
// }

// 使用:继承单个trait
trait Logger {
	def log(msg:String)
}

class ConsoleLogger extends Logger {
	override def log(msg: String): Unit = println("控制台消息:" + msg)
}

def main(args: Array[String]): Unit = {
	val logger = new ConsoleLogger
	logger.log("NullPoiter Exception...")
}

// 使用:继承多个trait
trait MessageSender {
	def send(msg:String)
}

trait MessageReceiver {
	def receive():String
}

class MessageWorker extends MessageSender with MessageReceiver {
	override def send(msg: String): Unit = println("发送消息:" + msg)

	override def receive(): String = "接收消息:你好!收到!"
}

def main(args: Array[String]): Unit = {
	val worker = new MessageWorker

	worker.send("你好, 收到没?")
	println(worker.receive())
}

// object继承trait
trait Logger {
	def log(msg:String)
}

object ConsoleLogger extends Logger {
	override def log(msg: String): Unit = println("控制台消息" + msg)
}

def main(args: Array[String]): Unit = {
	ConsoleLogger.log("hello")
}

定义具体的方法

trait Logger {
	def log(msg:String) = println(msg)
}

class UserService extends Logger {
	def add() = log("添加用户")
}

def main(args: Array[String]): Unit = {
	val service = new UserService
	service.add()
}

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

trait  Logger {
	// 具体字段
	val simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm")
	// 抽象字段
	val TYPE:String
	// 抽象方法
	def log(msg:String)
}

class ConsoleLogger extends Logger {
	override val TYPE: String = "控制台消息:"
	
	override def log(msg: String): Unit = println(s"${TYPE}:${simpleDateFormat.format(new Date)}:$msg")
}

def main(args: Array[String]): Unit = {
	val logger = new ConsoleLogger
	logger.log("hello")
}

使用 trait 实现模板模式

trait Logger {
	def log(msg:String)

	// 具体方法调用抽象方法
	def info(msg:String) = log("信息:" + msg)
	def warn(msg:String) = log("警告:" + msg)
	def error(msg:String) = log("错误:" + msg)
}

class ConsoleLogger extends Logger {
	override def log(msg: String): Unit = println(msg)
}

// 调用不同级别的日志输出
def main(args: Array[String]): Unit = {
	val logger = new ConsoleLogger
	
	logger.info("Call Action method")
	logger.warn("Type annotation required for Unit definition")
	logger.error("NullPoiter Exception")
}

对象混入 trait

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

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

// 使用
trait Logger {
    def log(msg:String) = println(msg)
}
class UserService
val service1 = new UserService with Logger

trait 实现调用链模式

责任链模式

在这里插入图片描述

trait 调用链

类继承了多个 trait 后,可以依次调用多个 trait 中的同一个方法,只要让多个 trait 中的同一个方法在最后都依次执行 super 关键字即可。类中调用多个 trait 中都有这个方法时,首先会从最右边的 trait 方法开始执行,然后依次往左执行,形成一个调用链条。
在这里插入图片描述
案例:
在这里插入图片描述

trait HandlerTrait {
	def handle(data:String) = {
		println("处理支付数据...")
	}
}

trait DataValidateTrait extends HandlerTrait {
	override def handle(data: String): Unit = {
		println("数据校验...")
		super.handle(data)
	}
}

trait SignatureValidateTrait extends HandlerTrait {
	override def handle(data: String): Unit = {
		println("签名校验...")
		super.handle(data)
	}
}

class PayService extends DataValidateTrait with SignatureValidateTrait {
	override def handle(data: String): Unit = {
		println("准备支付...")
		super.handle(data)
	}
}

def main(args: Array[String]): Unit = {
	val service = new PayService

	service.handle("支付数据")
}
// 准备支付...
// 签名校验...
// 数据校验...
// 处理支付数据...
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值