Scala的面向对象

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Scala的面向对象相关的知识,希望对你有一定的参考价值。

1.scala的类

(1)类的成员

class Student {
  //使用var定义一个可变的成员变量
  var age=18
  //使用val定义一不可变的成员变量
  val name="zy"
  //定义一个私有化成员变量(伴生对象仍然可以访问)
  private var id=1001
  //定义一个私有化成员变量(伴生对象也不可以访问)
  private[this] val address="anhui"

  //定义一个成员方法
  def running(): Unit ={
    println(this.name+"跑~")
  }
}

注意点
? - 在scala中声明类不要指定public,scala的文件名可以与类名不同。
? - 成员属性是否可以修改,取决于是否使用val修饰
? - 成员方法和属性能不能被访问,取决于修饰符,public(默认),private


(2)类的构造器

//在类上声明的是主构造器
class Student(val name:String,val age:Int) {
  //使用this为方法名,这个是辅助构造器
  def this(name:String,age:Int){
    this(name,age)
  }
}

主构造器的注意点:
? - 在类上定义的构造器称为主构造器
? - 主构造器包含了整个所有的类的代码块,所以,默认的定义的类中的所有能执行的代码都会执行
? - 主构造器中的参数如果没有使用任何修饰符,默认的就是 private[this] val
? - 主构造器中的参数如果使用val或者var修饰,就相当于一个普通的成员变量
辅助构造器的注意点:
? - 当主构造器被class private Student()修饰了,可以使用辅助构造器创建该类对象
? - 辅助构造器必须使用def修饰,并且方法名为this
? - 辅助构造器中的参数不能使用var或者val 修饰
? - 辅助构造器中的第一行代码必须是:调用其他的构造器


(3)类的私有化

//使用private修饰主构造器,表示私有化类
class Student private(val name: String, val age: Int) {
  def this(name: String, age: Int) {
    this(name,age)
  }
}
//使用 private[this]私有化类
class Person private[this](val name: String, val age: Int) {

}

注意点
? - 被private修饰的类,被私有化,不能其他类不能创建该类实例,但是伴生对象可以
? - 如果想让伴生对象都不能创建该类的实例,可以使用:class private[this]
? - 当主构造器被class private Student()修饰了,可以使用辅助构造器创建该类对象
??

2.伴生对象

?在scala的类中,与类名相同的单例对象叫做伴生对象。
? 特点:(假设现在有一个类:class Student ,和一个伴生对象:object Student)
? ? - class Student是object Student的伴生类
? ? - object Student是class Student的伴生对象
? ? - 类和伴生对象之间可以相互访问私有的方法和属性
? ? - 伴生类和伴生对象的名称相同
例:

//使用private修饰主构造器,表示私有化类
class Student private {
  private val name="zs"
  private val age=18
}
object Student{
  //在伴生对象中创建私有化类的对象
  val student=new Student()
  //在伴生对象中访问私有化的属性
  val name=student.name
  val age=student.age
}

单例对象
单例对象表示,被object修饰,但是没有自己的伴生类。
例:

object person{
   val name="zs"
   val age=18
}

特点
? - scala 语言并不支持静态成员,没有静态方法和静态字段,Scala 通过单例对象 object 来解决
? - 单例对象中的所有成员和方法都是static的
? - 单例对象它本身就是一个单例,(因为不需要去 new)


apply方法
? 在讲集合和数组的时候,可以通过 val intList=List(1,2,3)这种方式创建初始化一个列表对象, 其实它相当于调用 val intList=List.apply(1,2,3),只不过 val intList=List(1,2,3)这种创建方式更简洁一点,但我们必须明确的是这种创建方式仍然避免不了 new,它后面的实现机制仍然是 new 的方式,只不过我们自己在使用的时候可以省去 new 的操作。通常我们会在类的伴生对象中定义 apply 方法,当遇到【类名(参数 1,...参数 n)】时 apply 方法会被调用。
? Apply也叫构建函数:把一堆零散的值构建成一个对象返回
例:

object Test01 {
  def main(args: Array[String]): Unit = {
    //以下两种方式创建对象等效
    val list01 = List(1, 2, 3)
    val list02 = List.apply(1, 2, 3)
  }
}

特点
? - apply方法只能定义在object中。
? - apply方法可以重载, 还是被系统自动调用的
?

3.scala的抽象类

? 定义:抽象类是一种不能被实例化的类,抽象类中包括了若干不能完整定义的方法,这些方法由子 类去扩展定义自己的实现。
? 特点
? ? - 如果在父类中,有某些方法无法立即实现,而需要依赖不同的子类来覆盖,重写实现自 己不同的方法实现。此时可以将父类中的这些方法不给出具体的实现,只有方法签名,这 种方法就是抽象方法。
? ? - 一个类中如果有一个抽象方法,那么类就必须用 abstract 来声明为抽象类,此时抽象 类是不可以实例化的
? ? - 在子类中覆盖抽象类的抽象方法时,不需要使用 override 关键字
例:

abstract class Annimal {
  def runing()

  def eat()
}

class Cat extends Annimal {
  def runing(): Unit = {
    println("running~")
  }
  def eat(): Unit = {
    println("eatting~")
  }
}

?

4.scala的继承

例:

//父类
class Annimal {
  //被final修饰的无法被继承
  final private val name = "Annimal"

  def runing(): Unit = {
    println("running~")
  }

  def eat(): Unit = {
    println("eatting~")
  }
}

//子类
class Cat extends Annimal {
  //重写父类的方法
  override def runing(): Unit = {
    //调用父类原有的方法
    super.runing()
  }
}

注意
? - 在 Scala 中扩展类的方式 和 Java 一样都是使用 extends 关键字
? - 继承就代表,子类可以从父类继承父类的 field 和 method;然后子类可以在自己内部放 入父类所没有,子类特有的 field 和 method;使用继承可以有效复用代码
? - 子类可以覆盖父类的 field 和 method;但是如果父类用 final 修饰,field 和 method 用 final 修饰,则该类是无法被继承的,field 和 method 是无法被覆盖的
? - 如果子类要重写一个父类中的非抽象方法,则必须使用 override 关键字
? - 使用 super 关键字,显式地指定要调用父类的方法/属性
?

5.scala的类型检查和转换

技术分享图片
例:

object Test01 {
  def main(args: Array[String]): Unit = {
    val parent=new Annimal  //父类
    val chrild=new Cat      //子类

    //类型判断
    println(chrild.isInstanceOf[Annimal]) //true
    //类型获取
    println(classOf[Cat]) //class Cat
    //类型转换
    val annimal: Annimal = chrild.asInstanceOf[Annimal]
  }
}

//父类
class Annimal {
  //被final修饰的无法被继承
  final private val name = "Annimal"

  def runing(): Unit = {
    println("running~")
  }

  def eat(): Unit = {
    println("eatting~")
  }
}

//子类
class Cat extends Annimal {
  //重写父类的方法
  override def runing(): Unit = {
    //调用父类原有的方法
    super.runing()
  }
}

?

6.scala的特质 (Trait)

(1)特质的介绍

? Scala 和 Java 语言一样,采用了很强的限制策略,避免了多继承的问题。在 Java 语言中,只允许继承一个超类,该类可以实现多个接口,但 Java 接口有其自身的局限性:接口中只能包括抽象方法,不能包含字段、具体方法。Scala 语言利用 trait 解决了该问题,在 Scala 的 trait 中,它不但可以包括抽象方法还可以包含字段和具体方法。特质在底层实现是采用的Java的抽象类
例:

trait Annimal {
  val name = "Annimal"

  def runing(): Unit = {
    println("running~")
  }
  def eat()
}

(1)特质的基本使用

特质的特点
? - 特质里面的方法既可以实现,也可以不实现
? - 优先使用特质。一个类扩展多个特质是很方便的,但却只能扩展一个抽象类。
? - 特质不能设置带参数的构造:trait t(i: Int) {},参数 i 是非法的
? - 如果继承多个特质,使用第一个特质使用 extends,后面的使用 with
例:

trait Car {
}
trait Person{

}
class transformers extends Car with Person{

}

(2)特质作为接口使用

? 将特质中的方法全部定义成为抽象方法。类可以使用extends的方式继承特质。scala 不支持对类进行多继承,但是支持多重继承 trait,使用 with 关键字即可。类继承 trait 后,必须实现其中的抽象方法,实现时不需要使用 override 关键字
例:

trait mysqlDAO{
val id:Int
def add(o:Any):Boolean
def update(o:Any):Int
def query(id:String):List[Any]
}
//如果有多个 trait 的话,则使用 with 关键字即可
class DaoImpl extends MySQLDAO with Serializable{
// 给父类中的抽象字段赋值。
override val id = 12
// 实现抽象方法
def add(o:Any):Boolean = true
  def update(o:Any):Int = 1
def query(id:String):List[Any] = List(1,2,3)
}

(3)为实例对象混入 Trait

? 有时我们可以在创建类的对象时,指定该对象混入某个 Trait,这样,就只有这个对象混入该 Trait 的方法,而类的其他对象则没有。
例:

object Test01 {
  def main(args: Array[String]): Unit = {
    //会某一个对象混入特质
    var HTQ_DHF =new Person() with DHF
  }
}
trait transformers
trait HTQ extends transformers
trait DHF extends transformers
trait Person extends HTQ

(4)Trait 调用链

? scala 中支持让类继承多个 Trait 后,依次调用多个 Trait 中的同一个方法,只要让多个 Trait 的同一个方法中,在最后都执行 super.方法 即可。类中调用多个 Trait 中都有的这个方法时,首先会从最右边的 Trait 的方法开始执行,然后依 次往左执行,形成一个调用链条这种特性非常强大,其实就相当于设计模式中的责任链模式的一种具体实现依赖。
例:

object Test01 {
  def main(args: Array[String]): Unit = {
    val p=new Person_TraitChain("zhangxiaolong")
    p.sayHello
  }
}

trait Handler {
  //父类的trait 必须有实现体,不然会报错
  def handler(data:String): Unit ={
    println("Handler :"+data)
  }
}
trait Handler_A extends Handler{
  override def handler(data:String): Unit = {
    println("Handler_A :"+data)
    super.handler(data)
  }
}
trait Handler_B extends Handler{
  override def handler(data:String): Unit = {
    println("Handler_B :"+data)
    super.handler(data)
  }
}
trait Handler_C extends Handler{
  override def handler(data:String): Unit = {
    println("Handler_C :"+data)
    super.handler(data)
  }
}
class Person_TraitChain(val name:String) extends Handler_C with Handler_B with
  Handler_A{
  def sayHello={
    println("Hello "+name)
    handler(name)
  }
}

结果会打印:
技术分享图片
从右向左,依次调用

以上是关于Scala的面向对象的主要内容,如果未能解决你的问题,请参考以下文章

VSCode自定义代码片段9——JS中的面向对象编程

大数据学习:Scala面向对象和Spark一些代码读和问

scala入门教程:scala中的面向对象定义类,构造函数,继承

Scala 面向对象编程之对象

Scala入门系列:面向对象之object

8scala面向对象编程之对象