Scala入门(二) 面向对象

本文深入讲解Scala编程语言的核心概念,包括类与对象、构造器、伴生对象、继承与覆盖、抽象类与特质、模式匹配及样例类、Option类型等。通过详细解析,帮助读者掌握Scala的高级特性。

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

Class类

属性定义
  • val 只读属性 只有getter
  • var 读写属性 有getter又有setter
  • private val 只能在类内部和伴生对象中访问
  • private[this] val 只能在类内部访问
构造器
  • 主构造器
    • class Student(val name:String,val age:Int)
    • 类只有一个主构造器
    • 主构造器执行时, 会执行类定义中的所有语句
  • 辅助构造器
    • def this(name:String,age:Int,gender:String) { }
    • 类可以有多个辅助构造器
    • 辅助构造器的第一行必须是主构造器或者其他辅助构造器的调用

object对象

object简介
  • object 相当于 class 的单个实例,通常在里面放一些静态的 field 或者 method
  • object 作用:1.存放工具方法和常量2.高效共享单个不可变的实例3.单例模式
  • 使用时, 不需要new, 类似java的静态类 直接 单例对象名称.方法 即可调用
伴生对象
  • 在一个.scala文件中, 有一个Class A 还有一个同名的object A 则称这个 object是 class 的伴生对象,class 是 object 的伴生类

  • 伴生类和伴生对象的最大特点是,可以相互访问

  • apply() 方法

    • apply 方法通常是在伴生对象中实现的, 其目的是,通过伴生类的构造函数功能,来实现伴生对象的构造函数功能

    • 通常我们会在类的伴生对象中定义 apply 方法,当遇到类名(参数 1,…参数 n)时 apply 方法会被调用

      在apply方法内部,会new一个对应的类, 然后返回

  • main() 方法

    • scala 必须有一个main函数作为入口
    • main必须定义在object中
    • 也可以自定义object继承App Trait, 然后直接在类中编写原本在main方法中的代码

extends继承

  • 子类继承父类,与 Java 一样,也是使用 extends 关键字 不支持多继承类

  • Java 中的访问控制权限,同样适用于 Scala

  • 子类可继承父类的 field 和 method, 子类也可以有自己特有的 field 和 method

  • final

    • 父类用final修饰,则父类不能被继承
    • 父类的field 或 method被final修饰, 则被修饰的field和method不能被覆盖
  • protected

    • protected 子类可以直接访问父类的field和method

    • protected[this] 只允许在当前子类中访问父类的field和method

      子类创建的对象不能直接调用父类的field和method

  • val var

    • val 修饰的field 才允许被继承,在覆盖时,需要添加override关键字
    • var 修饰的只允许被引用 可以直接引用 因为var的值可变 覆盖没有意义 或者说没有覆盖的说法
  • override

    • 子类覆盖父类的非抽象方法时, 需要加override关键字
    • 覆盖方法后, 如果想要调用父类的同名方法, 使用super关键字
  • isInstanceOf asInstanceOf 模糊判断

    • isInstanceOf 判断对象是否为指定类或子类的对象 stu1.isInstanceOf[Student]
    • asInstanceOf 将对象转换为指定类型 stu1.asInstanceOf[Student]
    • 如果对象是 null,则 isInstanceOf 一定返回 false, asInstanceOf 一定返回null
  • getClass classOf 精准判断

    • getClass 可以精确地获取对象的类
    • classOf[XX] 可以精确的获取类
    • stu1.getClass == classOf[Student] true
  • 子类调用父类的constructor

    • 只能在子类的主 constructor 中调用父类的 constructor

      class Student(name:String,score:Double) extends Person(name,score)

      new Student 对象时 会调用父类的构造函数

    • 子类的辅助 constructor 是一定不可能直接调用父类的 constructor 的

    • 如果父类的构造函数已经定义过的 field,比如 name 和 age,子类再使用时就不用 val 或 var 来修饰了,否则会被认为,子类要覆盖父类的 field,且要求一定要使用 override 关键字

      class Student(override val name:String,score:Double) extends Person(name,score)

  • 抽象类

    抽象类

    • 一个类中,如果含有一个抽象方法或抽象 field,就必须使用 abstract 将类声明为抽象类

    • 父类中的方法编写成只含有方法签名,不含方法体的形式,这种形式就叫做抽象方法

      def sayHello:String

    • 父类中,定义了 field,但是没有给出初始值,则此 field 为抽象 field

      val age:Int

    • 在子类中覆盖抽象类的抽象方法时,可以不加 override 关键字

trait特质

  • trait具有接口特性
    • 在trait中可以定义抽象方法, 抽象field
    • 类通过extends继承trait, 继承后, 必须实现其抽象方法
    • scala不支持多继承类, 但是支持多重继承trait, 使用with进行连接
  • trait具有类特性
    • 在trait中也可以定义具体方法, 具体field
      • 如果是继承 class 获取的 field ,实际上还是定义在父类中的
      • 而继承 trait 获取的 field,就直接被添加到子类中了
  • trait混入
    • 在创建类的对象时, 为该对象混入某个trait, 表示只有这个对象才具有该trait中的方法, 而该类其他对象没有
      • val rose = new Student(“Rose”) with trait1
  • trait调用链 —> 责任链模式
    • Scala 中支持让类继承多个 trait 后,可依次调用多个 trait 中的同一个方法,只要让多个 trait 中的同一个方法,在最后都依次执行 super 关键字即可
    • 类中调用多个 trait 中都有的这个方法时,首先会从最右边的 trait 的方法开始执行,然后依次往左执行,形成一个调用链条
  • trait混合使用具体方法 抽象方法 —> 模板设计模式
    • 在 trait 中,可以混合使用具体方法和抽象方法
    • 可以让具体方法依赖于抽象方法 而抽象方法则可放到继承 trait 的子类中去实现
  • trait构造机制
    • 在 Scala 中,trait 也是有构造代码的,即在 trait 中,不包含在任何方法中的代码
    • 继承了 trait 的子类,其构造机制如下
      • 父类的构造函数先执行, class 类必须放在最左边
      • 多个 trait 从左向右依次执行
      • 构造 trait 时,先构造父 trait,如果多个 trait 继承同一个父 trait,则父 trait 只会构造一次
      • 所有 trait 构造完毕之后,子类的构造函数最后执行
  • traitt继承class
    • 在 Scala 中 trait 也可以继承 class,此时这个 class 就会成为所有继承该 trait 的子类的超级父类

模式匹配&样例类

Scala 有一个十分强大的模式匹配机制,可以应用到很多场合:类似 switch 语句 类型检查

Scala 还提供了样例类,对模式匹配进行了优化,可以快速进行匹配。

模式匹配
  • 匹配字符串

    name match {
        case "hadoop"     => println("大数据分布式存储和计算框架...")
        case "zookeeper"  => println("大数据分布式协调服务框架...")
        case "spark"      => println("大数据分布式内存计算框架...")
        //表示以上情况都不满足才会走最后一个
        case _            => println("我不认识你")
      }
    
  • 匹配类型

    value match {
        case x:Int                => println("Int=>"+x)
        //模式匹配的时候还可以添加守卫条件。如不符合守卫条件,将掉入 case _中。
        case y:Double if(y>=0)    => println("Double=>"+y)
        case z:String             => println("String=>"+z)
        case _                    => throw new Exception("not match exception")
      }
    
  • 匹配数组 元祖 集合

    //匹配数组
      val  arr=Array(1,3,5)
      arr match{
        case Array(1,_*)  =>println("1...")
        case Array(1,x,y) =>println(x+"---"+y)
        case Array(0)     =>println("only 0")
        case _            =>println("something else")
    
      }
    
      //匹配集合
      val list=List(0,3,6)
      list match {
        case 0::Nil        => println("only 0")
        ///println("x:"+x+" y:"+y+" z:"+z)
        case x::y::z::Nil  => println(s"x:$x y:$y z:$z")
        case 0::tail       => println("0....")
        case _             => println("something else")
    
      }
    
      //匹配元组
      val tuple=(1,3,5)
      tuple match{
        case (1,x,y)    => println(s"1,$x,$y")
        case (2,x,y)    => println(s"$x,$y")
        case _          => println("others...")
      }
    
样例类
  • case class 类型,是多例的,后面要跟构造参数。 case class Student(name:String)
  • case object 类型,是单例的。 case object Person
case class SubmitTask(id:String,name:String)
case class HeartBeat(time:Long)
case object CheckTimeOutTask
case object StopTask

value match{
    case SubmitTask(id,name)              =>println(s"$id----$name")
    case HeartBeat(time)                  =>println(s"$time")
    case CheckTimeOutTask                 =>println("check....")
    case StopTask                         =>println("stop.....")
}
Option类型

在 Scala 中 Option 类型用样例类来表示可能存在或者可能不存在的值(Option 的子类有Some 和 None)

  • Some 包装了某个值
  • None 表示没有值
val map=Map("a"->1,"b"->2)
//调用map中的get方法,传入一个key,返回一个Option类型
val v: Option[Int] = map.get("c")

v match{
	case Some(i)    =>println("存在..."+i)
	case None       =>println("不存在...")
}
偏函数

被包在花括号内没有 match 的一组 case 语句是一个偏函数,它是 PartialFunction[A, B]的一个实例,A 代表输入参数类型,B 代表返回结果类型,常用作输入模式匹配,偏函数最大的特点就是它只接受和处理其参数定义域的一个子集。

  def main(args: Array[String]) {
    println(func("two"))
    println(func2("two"))
  }
  
  val func:PartialFunction[String,Int]={
    case "one" =>  1
    case "two" =>  2
    case _     => -1
  }

  //定义一个普通的方法,通过match 和case 实现偏函数逻辑
  def func2(x:String):Int={
    x match {
      case "one" =>  1
      case "two" =>  2
      case _     => -1
    }

  }

Scala 协变、逆变、非变

Java中,如果有 A 是 B 的子类,但 Card[A]却不是 Card[B] 的子类;

而 Scala 中,只要灵活使用协变与逆变,就可以解决此类 Java 泛型问题

  • C[+T]:如果 A 是 B 的子类,那么 C[A]是 C[B]的子类。
  • C[-T]:如果 A 是 B 的子类,那么 C[B]是 C[A]的子类。
  • C[T]: 无论 A 和 B 是什么关系,C[A]和 C[B]没有从属关系。

Scala 上下界

在指定泛型类型时,有时需要界定泛型类型的范围,而不是接收任意类型。

Scala 的上下边界特性允许泛型类型是某个类的子类,或者是某个类的父类

类似java 的 <? super T> <? extends T>

  • U >: T <? super T>

这是类型下界的定义,也就是 U 必须是类型 T 的父类(或本身,自己也可以认为是自己的父类)。

  • S <: T ? <? extends T>

这是类型上界的定义,也就是 S 必须是类型 T 的子类(或本身,自己也可以认为是自己的子类)。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值