Scala学习第三天

本文介绍了Scala中的面向对象特性,包括单例对象、类、特质、抽象类和继承。详细讲解了单例对象的静态特性,类的构造器与访问权限,伴生类及其apply方法的应用。此外,还探讨了Scala中的特质,允许多重继承,并能实现动态混入。接着讨论了抽象类和final关键字的作用。最后,文章提到了模式匹配的用法,如匹配字符串、类型、数组、集合和元组。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

面向对象

单例对象

在Scala 中,是没有static 这个东西的,但是可以使用关键字object,使用object修饰的类是单例的,而且类中的方法/属性都是static的。

在scala中被object关键字修饰的类有如下特征:

  • 是单例的(内存中只有一个对象)
  • 类中的所有属性和方法都是静态的
  • 不需要通过new来创建对象,直接通过类名使用
  • 通常用于封装一些常量、工具类等  调用方式:类名.属性/方法
package day03

object ScalaSingleton {
  def saySomething(msg: String)={
    println(msg)
  }
}

object ScalaSingletonTest{

  def main(args: Array[String]): Unit = {
    ScalaSingleton.saySomething("hello scala")   //hello scala

    println(ScalaSingleton)
    println(ScalaSingleton)
    //day03.ScalaSingleton$@47f37ef1
    //day03.ScalaSingleton$@47f37ef1
  }
}

 Scala类

/*
* 在 Scala中,类并不用声明为 public。
* 如果你没有定义构造器, 类会有一个默认的空参构造器
*
* var 修饰的变量, 这个变量对外提供 getter setter 方法
* val 修饰的变量, 对外提供了 getter 方法,没有 setter
* */
class Student {
  //  _ 表示一个占位符, 编译器会根据你变量的具体类型赋予相应初始值
  // 注意: 使用_ 占位符是, 变量类型必须指定
  var name : String = _
  // 错误代码, val 修饰的变量不能使用占位符
  // val age: Int = _
  val age : Int = 10
}

object Test{
  val name : String = "zhangsan"
  def main(args: Array[String]): Unit = {
    // 调用空参构造器,可以加() 也可以不加
    val student = new Student()
    student.name = "lisi"
    // 类中使用 val 修饰的变量不能更改
    // student.age = 20
    println(s"student.name ====== ${student. name} ${student.age }")
    println ("Test.name======" + Test. name )
  }
}

定义在类后面的为类主构造器, 一个类可以有多个辅助构造器

/*
* Student1(val name: String, var age: Int)
* 定义个 2 个参数的主构造器
* */
class Student1 (val name: String, var age: Int) {
  var gender : String = _
  // 辅助构造器, 使用 def this
  // 在辅助构造器中必须先调用类的主构造器
  def  this(name: String, age:Int, gender: String){
    this(name, age)
    this. gender = gender
  }
}

object Test1{
  def main(args: Array[String]): Unit = {
    val s = new Student1( "laozhang", 38)
    println ( s"${s.name} ${s.age}")
    val s1 = new Student1( "laowang", 18,  "male")
    println ( s"${s1.gender}")
  }
}

访问权限

构造器的访问权限

/*
* Student1(val name: String, var age: Int)
* 定义个 2 个参数的主构造器
*
* private 加在主构造器前面标识这个主构造器是私有的, 外部不能访问这个构造器
* */
class Student2 private (val name: String, var age: Int) {
  var gender : String = _
  // 辅助构造器, 使用 def this
  // 在辅助构造器中必须先调用类的主构造器
  def this(name: String, age:Int, gender: String){
    this(name, age)
    this. gender = gender
  }
}

object Test2{
  def main(args: Array[String]): Unit = {
    val s1 = new Student2("laoYang", 18,"male")
    println ( s"${s1. gender }")
  }
}

成员变量的访问权限

/*
* private 加在主构造器前面标识这个主构造器是私有的, 外部不能访问这个构造器
*
* private var age
* age 在这个类中是有 getter setter 方法的
* 但是前面如果加上了 private 修饰, 也就意味着, age 只能在这个类的内部以及其伴生类对象中可以访 
* 问修改
* 其他外部类不能访问
* */
class Student3 private (val name: String,private var age: Int) {
  var gender : String = _
  // 辅助构造器, 使用 def this
  // 在辅助构造器中必须先调用类的主构造器
  def  this(name: String, age:Int, gender: String){
    this(name, age)
    this. gender = gender
  }
  // private[this]关键字标识该属性只能在类的内部访问, 伴生类不能访问
  private[ this]  val  province : String = "北京市"
  def getAge = 18
}

// 类的伴生对象
object Student3 {
  def main(args: Array[String]): Unit = {
    // 伴生对象可以访问类的私有方法和属性
    val s3 = new Student3("Angelababy", 30)
    s3.age = 29
    println ( s"${s3.age}")
    // println(s"${s3.province}") 伴生类不能访问
  }
}

类包的访问权限

/*
* private[包名] class 放在类声明最前面, 是修饰类的访问权限, 也就是说类在某些
 包下不可见或不能访问
*
* private[day03] class 代表 student4 在 day03 包下及其子包下可以见, 同级包中不能访问
*
* */
private[day03] class Student4(val name: String,private var age: Int)
{
  var xx : Int = _
}

object Student4{
  def main(args: Array[String]): Unit = {
    val s = new Student4("张三", 20)
    println ( s"${s.name}")
  }
}

伴生类/apply方法

在 Scala 中, 当单例对象与某个类共享同一个名称时,他被称作是这个类的伴生对象。必须在同一个源文件里定义类和它的伴生对象。类被称为是这个单例对象的伴生类。类和它的伴生对象可以互相访问其私有成员。

  1. 伴生类的主构造器可以私有化

  2. 在伴生对象中仍然可以调用伴生类私有化的构造器创建对象,所以可以在伴生对象的apply方法中完成对象创建以及一些初始化的动作(以这种方式暴漏对象创建接口)

除上述外,apply方法我们在调用的时候.apply可以省略,又简化了我们代码的编写

package day03

class ClassObject private (var name: String, var age: Int) {

}

object ClassObject{

  def apply(name: String,age: Int): ClassObject = new ClassObject(name,age)

  def getInstance(name: String, age: Int): ClassObject ={
    new ClassObject(name,age)
  }

  def main(args: Array[String]): Unit = {
    val classObject = new ClassObject("王五",19)
  }
}


package day03

object ClassObjectTest {

  def main(args: Array[String]): Unit = {
    val classObject = ClassObject.apply("sili", 18)
    println(classObject.name)

    val value = ClassObject("wangwu",22)
    println(value.name)
  }
}

特质(Trait)

Scala中的Trait相当于Java中的接口,实际上它比接口还功能强大。

与接口不同的是,它还可以定义属性和方法的实现。一般情况下 Scala 的类只能够继承单一父类,但是如果是 Trait(特质) 的话就可以继承多个,实现了多重继承。

trait T2 {
  // 定义一个属性
  val className: String = "scala"

  // 定义一个没有实现的方法
  def teacherSay(name: String)

  // 定义个带有具体的实现的方法
  def doSomething() = {
    println("该吃中午饭了...")
  }
}

特质的动态混入

package day03

class Student {
}
object Student{
  def main(args: Array[String]): Unit = {
    // 特质的动态混入:给student对象扩展ScalaTrait1特质功能和Fly功能
    val student = new Student with ScalaTrait1 with Fly
    student.dance("赵四")
    student.fly()
  }
}

//定义两个trait
package day03

trait ClassTrait1 {
  def hello(name: String): Unit ={
    println(s"hello ${name}")
  }

  def dance(name: String) = {
    println(s"$舞王{name}")
  }
}

package day03

trait Fly{
  def fly(): Unit ={
    println("i can fly...")
  }
}

也可以在类上直接继承多个特质,extend...with

class Student3Trait extends ScalaTrait1 with Fly{
 
}

抽象类

在 Scala 中, 使用 abstract 修饰的类称为抽象类. 在抽象类中可以定义属性、未实现的方法和具体实现的方法。

/*
* abstract 修饰的类是一个抽象类
* */
abstract class Animal {
  println ("Animal's r constructor  ....")
  // 定义一个 name 属性
  val name : String = "animal"
  // 没有任何实现的方法
  def sleep()
  // 带有具体的实现的方法
  def eat(f: String): Unit = {
    println ( s"$f")
  }
}

继承

final关键字

被 final 修饰的类不能被继承;

被 final 修饰的属性不能重写;

被 final 修饰的方法不能被重写。

type关键字

Scala 中可以通过 type 关键字来声明类型。  

type 相当于声明一个类型别名(Alias):

/*
* with 后面只能是特质
*
* 父类已经实现了的功能, 子类必须使用 override 关键字重写
* 父类没有实现的方法,子类必须实现,这个override可带可不带
* */
package day03

class TypeTraitImpl extends TypeTriat {
  //实现时指定该type类型变量的具体类型
  override type T = String
  
  override def learn(s: String): Unit = {
    
  }
}


package day03

trait TypeTriat {
  //type类型
  type T
  //当变量T的类型指定后s的类型也就随之确定
  def learn(s: T): Unit ={
    println("====>>" ,s)
  }
}

模式匹配

匹配字符串/类型/守卫

def main(args: Array[String]): Unit = {
  val arr = Array ( "AAA",  "BBB",  "CCC")
  val i = Random.nextInt(arr.length)
  println (i)
  val name = arr(i)
  println(name)
  name match {
    case "AAA" => println ("I am AAA")
    case "BBB" => println ("I am BBB")
    case _ => println ("Who are you ...")
  }

  //定义一个数组
  val arr :Array[Any] = Array ( "hello123", 1, 2.0, StudentTest, 2L)
  //取出一个元素
  val elem = arr(3)
  elem match {
    case x: Int => println ("Int" + x)
    case y: Double  if(y >= 0) => println ("Double"+ y) // if 守卫
    case z: String => println ("String"+ z)
    case w: Long => println ("long" + w)
    case StudentTest => {
      println ("case StudentTest")
      //throw new Exception("not match exception")
    }
    case _ => { // 其他任意情况
      println ( "no")
      println ( "default")
    }
  }
}

匹配数组

匹配数组的情况下属于拿着数组的整体结构进行匹配,而不是判断个别元素了

val arr = Array (1, 1, 7, 0, 2,3)
arr match {
  case Array (0, 2, x, y) => println (x + " " + y)  //x,y看作是一个占位符,和_效果相同
  case Array (2, 1, 7, y) => println ("only 0" + y)
  case Array (1, 1, 7, _*) => println ("0 ...") // _* 任意多个
  case _ => println ("something else")
}

匹配集合

val lst = List (0, 3, 4)
println ( lst .head)
println ( lst .tail)
lst match {
       // 0 :: Nil 代表集合中只有0一个元素
    case 0 :: Nil => println ("only 0")
      // x :: y :: Nil 代表两个元素插入到空集合中了,所以这里匹配的是2个元素的集合
    case x :: y :: Nil => println (s"x $x y $y")
      // :: 代表着要向一个集合的头部添加元素,::前面的值就是要插入的元素,此处其实就是0
      // 0 :: a   == List (0, 3, 4)
      // a = List(3,4)
    case 0 :: a => println (s"value : $a")
    case _ => println ("something else")
  
  //输出结果:
   // 0
   // List(3, 4)
   // value : List(3, 4)

}

匹配元组

val tup = (1, 3, 7)
tup match {
  case (3, x, y) => println (s"hello 123 $x ,$y")
  case (z, x, y) => println (s"$z, $x ,$y")
  case (_, w, 5) => println (w)
  case _ => println ( "else")
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值