Scala面向对象2

简介: Scala面向对象2

3 继承(extends)

3.1 简单继承


scala和Java一样,使用extends关键字来实现继承。可以在子类中定义父类中没有的字段和方法,或者重写父类的方法。

示例1:实现简单继承

class Person {
  var name = "super"
  def getName = this.name
}
class Student extends Person
object Main13 {
  def main(args: Array[String]): Unit = {
    val p1 = new Person()
    val p2 = new Student()
    p2.name = "张三"
    println(p2.getName)
  }
}

示例2:单例对象实现继承

class Person {
  var name = "super"
  def getName = this.name
}
object Student extends Person
object Main13 {
  def main(args: Array[String]): Unit = {
    println(Student.getName)
  }
}

3.2 override和super


  • 如果子类要覆盖父类中的一个非抽象方法,必须要使用override关键字
  • 可以使用override关键字来重写一个val字段
  • 可以使用super关键字来访问父类的成员

示例1:class继承class

class Person {
  val name = "super"
  def getName = name
}
class Student extends Person {
  // 重写val字段
  override val name: String = "child"
  // 重写getName方法
  override def getName: String = "hello, " + super.getName
}
object Main13 {
  def main(args: Array[String]): Unit = {
    println(new Student().getName)
  }
}

3.3 isInstanceOf和asInstanceOf


我们经常要在代码中进行类型的判断和类型的转换。在Java中,我们可以使用instanceof关键字、以及(类型)object来实现,在scala中如何实现呢?

scala中对象提供isInstanceOf和asInstanceOf方法。

  • isInstanceOf判断对象是否为指定类的对象
  • asInstanceOf将对象转换为指定类型
class Person3
class Student3 extends Person3
object Main3 {
  def main(args: Array[String]): Unit = {
    val s1:Person3 = new Student3
    // 判断s1是否为Student3类型
    if(s1.isInstanceOf[Student3]) {
      // 将s1转换为Student3类型
      val s2 =  s1.asInstanceOf[Student3]
      println(s2)
    }
  }
}

3.4 getClass和classOf


isInstanceOf 只能判断出对象是否为指定类以及其子类的对象,而不能精确的判断出,对象就是指定类的对象。如果要求精确地判断出对象就是指定类的对象,那么就只能使用 getClass 和 classOf 。

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

示例:

class Person4
class Student4 extends Person4
object Student4{
  def main(args: Array[String]) {
    val p:Person4=new Student4
    //判断p是否为Person4类的实例
    println(p.isInstanceOf[Person4])//true
    //判断p的类型是否为Person4类
    println(p.getClass == classOf[Person4])//false
    //判断p的类型是否为Student4类
    println(p.getClass == classOf[Student4])//true
  }
}

3.5 访问修饰符


Java中的访问控制,同样适用于scala,可以在成员前面添加private/protected关键字来控制成员的可见性。但在scala中,没有public关键字,任何没有被标为private或protected的成员都是公共的。

private[this]修饰符

被修饰的成员只能在当前类中被访问。或者可以理解为:只能通过this.来访问(在当前类中访问成员会自动添加this.)。

示例:

  1. 创建一个Person类
  • 添加一个private[this]修饰符的name字段,并赋值为"super"
  • 添加一个getName方法,获取name字段
  • 添加一个sayHelloTo方法,接收一个Person类型参数,尝试打印该参数的name字段
  1. 创建一个Person的伴生对象
  • 添加一个showName方法,接收一个Person类型参数,尝试打印该参数的name字段

代码:

class Person {
  // 只有在当前对象中能够访问
  private[this] var name = "super"
  def getName = this.name // 正确!
  def sayHelloTo(p:Person) = {
    println("hello" + p.name)     // 报错!无法访问
  }
}
object Person {
  def showName(p:Person) = println(p.name)  // 报错!无法访问
}

protected[this]修饰符

被修饰的成员只能在当前类和当前子类中被访问。也可以理解为:当前类通过**this.访问或者子类通过this.**访问

示例:

  1. 将Person类的name字段访问修饰符改为protected[this]
  2. 创建一个Student类
  • 添加一个showName方法,在方法中访问name字段
  • 添加一个sayHelloTo2方法,接收一个Person类型参数,在方法中打印该参数的name字段
class Person {
  // 只有在当前对象以及继承该类的当前对象中能够访问
  protected[this] var name = "super"
  def getName = {
    // 正确!
    this.name
  }
  def sayHelloTo1(p:Person) = {
    // 编译错误!无法访问
    println(p.name)
  }
}
object Person {
  def sayHelloTo3(p:Person) = {
    // 编译错误!无法访问
    println(p.name)
  }
}
class Student extends Person {
  def showName = {
    // 正确!
    println(name)
  }
  def sayHelloTo2(p:Person) = {
    // 编译错误!无法访问
    println(p.name)
  }
}

3.6 调用父类的constructor


实例化子类对象,必须要调用父类的构造器,在scala中,只能在子类的主构造器中调用父类的构造器

步骤:

  1. 创建一个Person类,编写带有一个可变的name字段的主构造器
  2. 创建一个Student类,继承自Person类
  • 编写带有一个name参数、clazz班级字段的主构造器
  • 调用父类的构造器
  1. 创建main方法,创建Student对象实例,并打印它的姓名、班级

代码:

class Person5(var name:String)
// 直接在父类的类名后面调用父类构造器
class Student5(name:String, var clazz:String) extends Person5(name)
object Main5 {
  def main(args: Array[String]): Unit = {
    val s1 = new Student5("张三", "三年二班")
    println(s"${s1.name} - ${s1.clazz}")
  }
}

3.7 抽象类


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

不完整定义有两种情况:

  1. 方法没有方法体
  2. 变量没有初始化

没有方法体的方法称为抽象方法,没有初始化的变量称为抽象字段。定义抽象类和Java一样,在类前面加上abstract关键字就可以了

3.7.1 抽象方法

示例1:

设计4个类,表示上述图中的继承关系,每一个形状都有自己求面积的方法,但是不同的形状计算面积的方法不同。

步骤:

  1. 创建一个Shape抽象类,添加一个area抽象方法,用于计算面积
  2. 创建一个Square正方形类,继承自Shape,它有一个边长的主构造器,并实现计算面积方法
  1. 创建一个长方形类,继承自Shape,它有一个长、宽的主构造器,实现计算面积方法
  2. 创建一个圆形类,继承自Shape,它有一个半径的主构造器,并实现计算面积方法
  3. 编写main方法,分别创建正方形、长方形、圆形对象,并打印它们的面积

代码:

// 创建形状抽象类
abstract class Shape {
  def area:Double
}
// 创建正方形类
class Square(var edge:Double /*边长*/) extends Shape {
  // 实现父类计算面积的方法
  override def area: Double = edge * edge
}
// 创建长方形类
class Rectangle(var length:Double /*长*/, var width:Double /*宽*/) extends Shape {
  override def area: Double = length * width
}
// 创建圆形类
class Cirle(var radius:Double /*半径*/) extends Shape {
  override def area: Double = Math.PI * radius * radius
}
object Main6 {
  def main(args: Array[String]): Unit = {
    val s1:Shape = new Square(2)
    val s2:Shape = new Rectangle(2,3)
    val s3:Shape = new Cirle(2)
    println(s1.area)
    println(s2.area)
    println(s3.area)
  }
}

3.7.2 抽象字段

示例2:

步骤:

  1. 创建一个Person抽象类,它有一个String抽象字段WHO_AM_I
  2. 创建一个Student类,继承自Person类,重写WHO_AM_I字段,初始化为学生
  1. 创建一个Policeman类,继承自Person类,重写WHO_AM_I字段,初始化警察
  2. 添加main方法,分别创建Student/Policeman的实例,然后分别打印WHO_AM_I

代码

// 定义一个人的抽象类
abstract class Person6 {
  // 没有初始化的val字段就是抽象字段
  val WHO_AM_I:String
}
class Student6 extends Person6 {
  override val WHO_AM_I: String = "学生"
}
class Policeman6 extends Person6 {
  override val WHO_AM_I: String = "警察"
}
object Main6 {
  def main(args: Array[String]): Unit = {
    val p1 = new Student6
    val p2 = new Policeman6
    println(p1.WHO_AM_I)
    println(p2.WHO_AM_I)
  }
}

3.8 匿名内部类


匿名内部类是没有名称的子类,直接用来创建实例对象。Spark的源代码中有大量使用到匿名内部类。

示例:

  1. 创建一个Person10抽象类,并添加一个sayHello抽象方法
  2. 添加main方法,通过创建匿名内部类的方式来实现Person10
  3. 调用匿名内部类对象的sayHello方法

代码:

abstract class Person7 {
  def sayHello:Unit
}
object Main7 {
  def main(args: Array[String]): Unit = {
    // 直接用new来创建一个匿名内部类对象
    val p1 = new Person7 {
      override def sayHello: Unit = println("我是一个匿名内部类")
    }
    p1.sayHello
  }
}


目录
相关文章
|
5月前
|
设计模式 Java Scala
Scala 面向对象【中】
Scala 面向对象【中】
|
5月前
|
Java Scala Python
Scala面向对象【上】
Scala面向对象【上】
|
5月前
|
分布式计算 Java Scala
Scala:面向对象、Object、抽象类、内部类、特质Trait(二)
Scala:面向对象、Object、抽象类、内部类、特质Trait(二)
63 0
|
5月前
|
大数据 Scala
Scala面向对象练习题34道
Scala面向对象练习题34道
71 0
|
5月前
|
Java Scala
Scala面向对象【下】
Scala面向对象【下】
|
8月前
|
Java Scala
Scala面向对象4
Scala面向对象4
27 0
|
8月前
|
Scala
Scala面向对象3
Scala面向对象3
25 1
|
8月前
|
Java 编译器 Scala
Scala面向对象1
Scala面向对象1
36 0
|
SQL JSON 前端开发
Scala的面向对象与函数编程
Scala的面向对象与函数编程
Scala的面向对象与函数编程
|
存储 算法 Java
Scala学习三-面向对象
前面我们已经学习了特质类似接口,其可以被继承,同时如果需要继承多个特质的话,则需要使用extends…with…进行继承。其类似java中的接口和抽象方法的结合体,但又比java中的其要强大,因为其可以定义抽象字段和普通字段、抽象方法和普通方法。而在java中接口中可以定义常量,不能定义变量。同时特质还可以继承class类,而在java中接口通常是用来实现的。 Object继承trait
116 0
Scala学习三-面向对象