Scala 类和对象

友情推荐

Scala 基础语法

Scala 类和对象

Scala 高级语法

参考
Scala 参考文档 (scala-lang.org)
[Scala 教程 ](

类和对象

Scala 不论是类、还是抽象类、还是特质,都是使用 extends 关键字

创建类

// 第一种
// 如果类是空的,没有任何成员,可以省略{}
class Student

// 第二种
class Teacher {
  //
}

创建对象

// 第一种
// 如果构造器的参数为空,可以省略()
val stu1 = new Student()

// 第二种
val stu2 = new Student

成员变量的定义和访问

说明

① 在类中使用 var/val 来定义成员变量

② 对象直接使用成员变量名称来访问成员变量

定义成员变量

// 第一种:scala 类型自动推断,并设置初始化值
class Student {

  var name = ""
  var age = 0

}

// 第二种
// 使用下划线进行初始化
class Teacher {
  
  var name: String = _
  var age: Int = _

}

访问成员变量

val teacher1 = new Teacher()
teacher1.name = "Jack"
println(teacher1.name)
println(teacher1.age)

成员方法的定义和访问

定义方法

class Teacher {

  var name: String = _
  var age: Int = _

  /**
   * 课程上课方法
   *
   * @param course 课程
   */
  def teach(course: String): Unit = {
    println(s"开始上[${course}]课!")
  }
}

访问方法

val teacher = new Teacher()
teacher.teach("语文")

在这里插入图片描述

访问修饰符

① Scala 也可以通过访问修饰符,来控制成员变量和成员方法是否可以被访问

② 在 Scala 中,没有 public 关键字,任何没有被标为 privateprotected 的成员都是公共的

// 第一种
class Teacher {
  private var name: String = _
  private var age: Int = _

  def getName: String = name
  def setName(name: String): Unit = this.name = name

  def getAge: Int = age
  def setAge(age: Int): Unit = this.age = age
}
// 第二种
private var name: String = _
private var age: Int = _

def getName() = this.name
def setName(name: String) = this.name = name

def getAge() = this.age
def setAge(age: Int) = this.age = age

类的构造器

① 主构造器

② 辅助构造器

主构造器

① 构造器的参数列表是直接定义在类名后面,添加了 val/var 表示直接通过主构造器定义成员变量

② 构造器参数列表可以指定默认值

③ 创建实例,调用构造器可以指定字段进行初始化

④ 整个 class 中除了字段定义和方法定义的代码都是构造代码

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

// 示例
class Student(var name: String = "", var age: Int = 0) {
  println(s"姓名:${name},年龄:${age}")
}
val student = new Student("Kyle", 23)
println(student.name)
println(student.age)

辅助构造器

① 允许通过多种方式,来创建对象,可以定义其他更多的构造器

除了主构造器之外的构造器称为辅助构造器

辅助构造器必须要调用主构造器或者其他辅助构造器

// 格式
def this(参数名:类型, 参数名:类型) {
    // 第一行需要调用主构造器或者其他构造器
    // 构造器代码
}

// 示例
class Student(var name: String = "", var gender: String = "") {

  println(s"姓名:${name},性别:${gender}")

  def this(arr: Array[String]) = {
    // 辅助构造器必须要调用主构造器或者其他辅助构造器
    this(arr(0), arr(1))
  }

}
//  调用
val student = new Student(Array("Kyle","male"))
println(student.name)
println(student.gender)

单例对象

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

定义单例对象

① 定义单例对象和定义类很像,就是把 class 换成 object

② 在 object 中定义的成员变量类似于 Java 的静态变量

可以使用 object 直接引用成员变量

object Person {

  val AREA = "China"

  def main(args: Array[String]): Unit = {
    println(Person.AREA)
  }

}

定义成员方法

// 定义一个日期工具类
object DateUtil {

  def getDateString(): String ={
    java.time.LocalDate.now().toString
  }
}
// 调用
DateUtil.getDateString()

程序入口

Scala 中没有静态方法,在 Scala 中,这个 main 方法必须放在一个单例对象中

① main 方法

object Demo {

  def main(args: Array[String]): Unit = {
    println(DateUtil.getDateString())]
  }

}

② 实现 App Trait 来定义入口

object Demo extends App {
  
  println(DateUtil.getDateString())

}

伴生对象

由于 Scala 中没有静态成员变量、静态成员方法等,通过伴生对象就可以实现和 java 一样在一个类中即有实例成员又有静态成员

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

定义伴生对象

① 伴生对象必须要和伴生类一样的名字

② 伴生对象和伴生类在同一个 scala 源文件中

③ 伴生对象和伴生类可以互相访问 private 属性

object AssociatedDemo extends App {

  class Worker {

    def work(): Unit = {
      println(s"机器人${WORKER_NAME}开始工作!")
    }

  }

  object Worker {

    val WORKER_NAME = "Jack_01"

  }

  new Worker().work()

}

private[this] 访问权限

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

// 示例:该代码编译报错,因为伴生对象不能访问伴生类中 权限为 private[this] 的成员,去掉 [this] 即可
object AssociatedDemo extends App {

  class Worker(private[this] var workId: String) {

    def work(): Unit = {
      println(s"机器人${WORKER_NAME}开始工作!")
    }

  }

  object Worker {

    val WORKER_NAME = "Jack_01"

    def printWorkId(worker: Worker): Unit = {
      println(worker.workId)
    }

  }

  val worker1 = new Worker("001")
  printWorkId(worker1)
  
}

apply方法

apply 方法使创建对象变得更容易,不需要写 new

// apply 方法定义格式
object 伴生对象名 {
    def apply(参数名:参数类型, 参数名:参数类型...) = new(...)
}
// 示例
object AssociatedDemo extends App {

  class Worker(var workId: String, var workDay: Int) {
  }

  object Worker {
    
    def apply(workId: String, workDay: Int) = new Worker(workId, workDay)

  }

  // 创建对象
  val worker1 = Worker("001", 20)

}

继承

继承的定义

① Scala 和 Java 一样,使用 extends 关键字来实现继承

② 可以在子类中定义父类中没有的字段和方法,或者重写父类的方法

③ 类和单例对象都可以从某个父类继承

class/object 子类 extends 父类 {
    ..
}

类继承

class Person {
  
  var name = ""
  def getName = this.name
}

class Student extends Person
  

// main 方法
def main(args: Array[String]): Unit = {
    val p1 = new Person()
    val p2 = new Student()

    p2.name = "Kyle"

    println(p2.getName)
  }

单例对象继承

class Person {
  var name = ""

  def getName = this.name
}

object Student extends Person

// main 方法
  def main(args: Array[String]): Unit = {

    println(Student.getName)
  }

override 和 super

① 子类要覆盖父类中的一个方法,必须要使用 override 关键字

② 使用 override 来重写一个 val 字段

③ 使用 super 关键字来访问父类的成员

class Person {
  
  val name = "Preson"
  def getName = name
}

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

// main 方法
def main(args: Array[String]): Unit = {
  println(new Student().getName)
}

类型转换及判断

isInstanceOf / asInstanceOf

① isInstanceOf 判断对象是否为指定类的对象

// 判断对象是否为指定类型
val trueOrFalse:Boolean = 对象.isInstanceOf[类型]

// 示例
class Person
class Student extends Person

val stu1:Person = new Student

println(stu1.isInstanceOf[Student]) // true
println(stu1.isInstanceOf[Person]) // true

② asInstanceOf 将对象转换为指定类型

// 将对象转换为指定类型
val 变量 = 对象.asInstanceOf[类型]

// 示例
val stu1:Person = new Student
if(stu1.isInstanceOf[Student]) {
  // 类型转换
   val stu2 =  stu1.asInstanceOf[Student]
}

etClass 和 classOf

isInstanceOf 只能判断对象是否为 指定类以及其子类 的对象,而不能精确的判断出,对象就是指定类的对象

如果要求精确地判断出对象就是指定类的对象,那么就只能使用 getClass 和 classOf

① getClass 可以精确获取对象的类型

② classOf[x ]可以精确获取类型

class Person
class Student extends Person

val p:Person = new Student

println(p.getClass == classOf[Student]) // true
println(p.getClass == classOf[Person]) // false

抽象类

抽象类的定义

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

① 方法没有方法体(抽象方法)

② 变量没有初始化(抽象字段)

// 格式
// 定义抽象类
abstract class 抽象类名 {
  // 定义抽象字段
  val 抽象字段名:类型
  // 定义抽象方法
  def 方法名(参数:参数类型,参数:参数类型...):返回类型
}
abstract class Factory {

  val name: String

  def pipeline(pipe:String,workNo:String):String

}

抽象方法

定义抽象类,定义多个继承类,抽象方法为计算面积,按照不同的计算方式重写计算面积的方法

// 抽象类
abstract class Shape {
  def area:Double
}

// 创建正方形类
class Square(var edge:Double) extends Shape {
  // 实现父类计算面积的方法
  override def area: Double = edge * edge
}

// 创建圆形类
class Cirle(var radius:Double) extends Shape {
  override def area: Double = Math.PI * radius * radius
}

// 计算
val s1:Shape = new Square(2)
val s3:Shape = new Cirle(2)

println(s1.area)
println(s2.area)

抽象字段

abstract class Person {
  val JOB :String
}

class Teacher extends Person {
  override val JOB: String = "教师"
}

class Student extends Person {
  override val JOB: String = "学生"
}

val p1 = new Teacher
val p2 = new Student
println(p1.JOB)
println(p2.JOB)

匿名内部类

匿名内部类是没有名称的子类,直接用来创建实例对象

// 格式
val/var 变量名 = new/抽象类 {
    // 重写方法
}
abstract class Teacher {
  def teach:Unit
}

def main(args: Array[String]): Unit = {
  // 直接用new来创建一个匿名内部类对象
  val teacher = new Teacher {
    override def teach: Unit = println("开始上语文课")
  }
  
  teacher.teach
}

特质(trait) – 接口

特质的定义

① 特质是 Scala 中代码复用的基础单元

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

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

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

⑤ 继承多个 trait,则使用 with 关键字

// 定义特质
trait 名称 {
    // 抽象字段
    // 抽象方法
    // 具体字段
    // 具体方法
}
// 继承特质
classextends 特质1 with 特质2 {
    // 字段实现
    // 方法实现
}

特质作为接口使用

① class 继承单个特质

trait Logger {
    // 抽象方法
    def log(message:String)
  }

class ConsoleLogger extends Logger {
  override def log(message: String): Unit = println("控制台日志:" + message)
}

def main(args: Array[String]): Unit = {
    val logger = new ConsoleLogger
    logger.log("这是一条日志")
  }

② class 继承多个特质

trait MessageSender {
    def send(msg:String)
}

trait MessageReceive {
    def receive():String
}

class MessageWorker extends MessageSender with MessageReceive {
  
    override def send(msg: String): Unit = println(s"发送消息:${msg}")

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

③ Object 继承特质

trait Logger {
    def log(message:String)
}

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

def main(args: Array[String]): Unit = {
    ConsoleLogger.log("程序退出!")
}

定义具体的方法

trait LoggerDetail {
  // 在trait中定义具体方法
  def log(msg:String) = println(msg)
}

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

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

定义具体字段和抽象字段

① 在 trait 中既可以定义抽象字段,又可以定义具体字段

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

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

trait Logger{
  val sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss")
  val TYPE :String
  def log(msg:String)
}

class ConsoleLogger extends Logger{
  override val TYPE: String = "info"
  override def log(msg: String): Unit = {
    val info = s"${TYPE} ${sdf.format(new Date)}:"+msg
    println(info)
  }
}

对象混入特质

Scala 中可以将 trait 混入到对象中,就是将 trait 中定义的方法、字段添加到一个对象中,给对象额外添加一些功能

val/var 对象名 = newwith 特质
 trait Logger {
    def log(msg:String) = println(msg)
  }

  class UserService

  def main(args: Array[String]): Unit = {
    val service = new UserService with Logger
    service.log("混入的方法")
  }

trait 的构造机制

trait 的加载顺序

① 执行父类 A 的构造器

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

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

④ 执行子类构造器

class A extends B with C with D {
    // 字段实现
    // 方法实现
}
trait Logger {
    println("执行Logger构造器")
}

trait MyLogger extends Logger {
    println("执行MyLogger构造器")
}

trait TimeLogger extends Logger {
    println("执行TimeLogger构造器")
}

class Person{
    println("执行Person构造器")
}

class Student extends Person with TimeLogger with MyLogger {
    println("执行Student构造器")
}

def main(args: Array[String]): Unit = {
    new Student
}

// 执行Person构造器
// 执行Logger构造器
// 执行TimeLogger构造器
// 执行MyLogger构造器
// 执行Student构造器

trait 继承 class

trait 也可以继承 class 的,特质会将 class 中的成员都继承下来

class MyUtil {
    def printMsg(msg:String) = println(msg)
}

trait Logger extends MyUtil {
    def log(msg:String) = printMsg("Logger:" + msg)
}

class Person extends Logger {
    def sayHello() = log("你好")
}

def main(args: Array[String]): Unit = {
    val person = new Person
    person.sayHello()
}

样例类

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

定义样例类

① 构造器的每个参数都默认成为 val 修饰(val可以省略),除非显式被声明为 var,但是并不推荐这么做

② 自动在伴生对象中提供了 apply 方法,所以后面我们可以不使用 new 关键字就可构建对象

③ 自动提供了 unapply 方法,让我们可以通过模式匹配来获取类属性,是 Scala 中抽取器的实现和模式匹配的关键方法

自动生成了toString、equals、hashCode 和 copy 方法,除非我们另外再显示给出这些方法的定义

// 语法格式
case class 样例类名([var/val] 成员变量名1:类型1, 成员变量名2:类型2, 成员变量名3:类型3)
// 示例
case class Student(name:String, age:Int)

def main(args: Array[String]): Unit = {
  
  val student = Person("Kyle", 20)
  println(student)
  
}

可变成员变量

// 可变的才能修改,不然会编译报错
case class Student(var name:String, var age:Int)

val student = Student("Kyle", 20)
student.age = 23

样例类的方法

① apply 方法

apply 方法可以让我们快速地使用类名来创建对象

② toString 方法

③ equals 方法

样例类自动实现了 equals 方法,可以直接使用 == 比较两个样例类是否相等,即所有的成员变量是否相等

④ hashCode 方法

样例类自动实现了 hashCode 方法,如果所有成员变量的值相同,则 hash 值相同,只要有一个不一样,则 hash 值不一样

⑤ copy 方法

样例类实现了 copy 方法,可以快速创建一个相同的实例对象,可以使用带名参数指定给成员进行重新赋值

val stu1 = Student("Kyle", 20)
stu2 = stu1.copy(name = "Jack')

样例对象

使用 case object 可以创建样例对象。样例对象是单例的,而且它没有主构造器

// 语法格式
case object 样例对象名

定义枚举

trait Sex
case object Male extends Sex
case object Female extends Sex  

case class Student(name:String, sex:Sex)

def main(args: Array[String]): Unit = {
  val student = Student("Kyle", Male)
  println(student)
}

模式匹配

模式匹配的使用场景

① switch 语句

② 类型查询

③ 使用模式匹配快速获取数据

模式匹配的几种模式

① 简单匹配模式

② 类型匹配模式

③ 守卫

④ 样例匹配模式

简单模式匹配

// 语法格式
变量 match {
    case "常量1" => 表达式1
    case "常量2" => 表达式2
    case "常量3" => 表达式3
    case _ => 表达式4      // 默认配
}

注:无需使用到匹配到的变量,可以使用下划线代替

val season = "01"

val result = name match {
    case "01" => "春季"
    case "02" => "夏季"
    case "03" => "秋季"
    case "04" => "冬季"
    case _ => "未匹配"
}

println(result)

匹配类型

根据不同的数据类型,来执行不同的逻辑,也可以使用 match 表达式来实现

val a:Any = "test"

val result = a match {
    case _:String => "String"
    case _:Int => "Int"
    case _:Double => "Double"
}

println(result)

守卫

case 语句中添加 if 条件判断,称为 守卫

val a = 3

a match {
    case _ if( a >= 0 && a <= 3) => println("[0-3]")
    case _ if( a >= 4 && a <= 8) => println("[4-8]")
    case _ => println("未匹配")
}

匹配样例类

Scala 可以使用模式匹配来匹配样例类,从而可以快速获取样例类中的成员数据

case class Student(name:String, age:Int)
case class Score(score:Int)

val student:Any = Student("Kyle", 20)
val score:Any = Score(98)

order1 match {
    case Student(name, age) => println(s"姓名:${name} 年龄:${age}")
    case Score(score) => println(s"成绩为:${score}")
    case _ => println("未匹配")
}

变量声明中的模式匹配

在定义变量的时候,可以使用模式匹配快速获取数据

示例 | 获取数组中的元素

// 需求
// 生成包含 1-10 数字的数组,使用模式匹配分别获取第二个、第三个、第四个元素
val arr = (1 to 10).toArray
// 第一种方法
val Array(a,b,c,d,e,f,g,h,i,j)=arr
println(b,c,d)

// 第二种方法
val Array(_, x, y, z, _*) = arr
println(x, y, z)

示例 | 获取List中的数据

// 需求
// 生成包含 0-10 数字的列表,使用模式匹配分别获取第一个、第二个元素
val list = (1 to 10).toList
val x :: y :: tail = list
println(x, y)

提取器(Extractor)

提取器主要用来提取类中的成员变量,在模式匹配中,由于只有样例类提供了 applyunapply 方法,所以可以实现成员变量的提取,为了让所有的类都可以实现成员变量的提取,因此出现了提取器

定义提取器

伴生对象中的 apply 方法,可以用类名来快速构建一个对象

伴生对象中的 unapply 方法,可以将该类的对象,拆解为一个个的元素

// 语法格式
override def unapply(stu:Student):Option[(类型1, 类型2, 类型3...)] = {
    if(stu != null) {
        Some((变量1, 变量2, 变量3...))
    }
    else {
        None
    }
}

实现提取器

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

object Student {
    def apply(name:String, age:Int) = {
        new Student(name, age)
    }

    def unapply(student:Student) = {
        val tuple = (student.name, student.age)

        Some(tuple)
    }
}

def main(args: Array[String]): Unit = {
    val zhangsan = Student("Kyle", 23)

    zhangsan match {
        case Student(name, age) => println(s"${name} => ${age}")
    }
}

泛型

类 class 和特质 trait、方法都支持泛型,集合涉及到泛型的情况比较多

定义一个泛型方法

// 语法格式
def 方法名[泛型名称](..) = {
    //...
}
// 获取集合中的最后一个元素
def getLast(arr:Array[Int]) = arr(arr.length)

def main(args: Array[String]): Unit = { 
  println(getLast(Array(1,2,3,4,5)))
}

定义一个泛型类

注意:范型类的多个成员变量的类型可以不一致

// 语法格式
// 注意:成员变量的类型可以不一致
class[T](val 变量名: T)
case class Pipe[T](var a:T, var b:T)

def main(args: Array[String]): Unit = { 
  Pipe("step1","start")
  Pipe(1,0.2)
  Pipe("step2", Some(2.0))
}

上下界(上界)

// 定义上界
// 使用 <: 类型名 表示给类型添加一个上界,表示泛型参数必须要从该类(或本身)继承
class[T<: 类型](val 变量名: T)
class Person
class Student extends Person

def demo[T <: Person](a:Array[T]) = println(a)

def main(args: Array[String]): Unit = {
    demo(Array(new Person))
    demo(Array(new Student))
    // 运行出错,必须是Person的子类
    // demo(Array("Kyle"))
}

上下界(下界)

// 定义下界
// 下界是必须是某个类的父类(或本身)
class Person
class Student extends Person
class Gardener extends Teacher

def demo[T >: Student](array:Array[T]) = println(array)

def main(args: Array[String]): Unit = {
    demo(Array(new Person))
    demo(Array(new Student))
    // 编译出错:Gardener是Teacher的子类
    // demo(Array(new Gardener))
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值