scala08——Scala面向对象之继承

Scala中继承的概念

Scala 中,让子类继承父类,与 Java 一样,也是使用 extends 关键字;

继承就代表,子类可继承父类的 field 和 method ,然后子类还可以在自己的内部实现父类没有的,子类特有的 field 和method,使用继承可以有效复用代码;

子类可以覆盖父类的 field 和 method,但是如果父类用 final 修饰,或者 field 和 method 用 final 修饰,则该类是无法被继承的,或者 field 和 method 是无法被覆盖的。

private 修饰的 field 和 method 不可以被子类继承,只能在类的内部使用;

field 必须要被定义成 val 的形式才能被继承,并且还要使用 override 关键字。 因为 var 修饰的 field 是可变的,在子类中可直接引用被赋值,不需要被继承;即 val 修饰的才允许被继承,var 修饰的只允许被引用。继承就是改变、覆盖的意思。

Java 中的访问控制权限,同样适用于 Scala。
public
protected
default
private

可以使用 protected[this] 关键字, 访问权限的保护范围:只允许在当前子类中访问父类的 field 和 method,不允许通过其他子类对象访问父类的 field 和 method。

isInstanceOf 和 asInstanceOf

如果实例化了子类的对象,但是将其赋予了父类类型的变量,在后续的过程中,又需要将父类类型的变量转换为子类类型的变量,需要:
首先,需要使用 isInstanceOf 判断对象是否为指定类的对象,如果是的话,则可以使用 asInstanceOf 将对象转换为指定类型;
p.isInstanceOf[XX] 判断 p 是否为 XX 对象的实例;p.asInstanceOf[XX] 把 p 转换成 XX 对象的实例
如果没有用 isInstanceOf 先判断对象是否为指定类的实例,就直接用 asInstanceOf 转换,则可能会抛出异常;
如果对象是 null,则 isInstanceOf 一定返回 false, asInstanceOf 一定返回 null;
Scala与Java类型检查和转换

ScalaJava
obj.isInstanceOf[C]obj instanceof C
obj.asInstanceOf[C]( C )obj
classOf[C]C.class

getClass 和 classOf

isInstanceOf 只能判断出对象是否为指定类以及其子类的对象,而不能精确的判断出,对象就是指定类的对象;如果要求精确地判断出对象就是指定类的对象,可以使用 getClass 和 classOf ;
p.getClass 可以精确地获取对象的类,
classOf[XX] 可以精确的获取类,然后使用 == 操作符即可判断;

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

使用模式匹配进行类型判断

实际的开发中,大量的地方使用模式匹配的语法进行类型的判断,这种方式更加地简洁明了,而且代码的可维护性和可扩展性也非常高。
使用模式匹配,功能性上来说,与 isInstanceOf 的作用一样,主要判断是否为该类或其子类的对象即可,不是精准判断。
等同于 Java 中的 switch case 语法

class Person{}
class Student extends Person
object Student{
  def main(args: Array[String]) {
    val p:Person=new Student
    p match {
      // 匹配是否为Person类或其子类对象
      case per:Person => println("This is a Person's Object!")
      // 匹配所有剩余情况
      case _  =>println("Unknown type!")
    }
  }
}

抽象类

abstract class Element {
  def contents: Array[String]
}

在这个类中,成员 contents 使用了没有定义具体实现的方法来定义,这个方法称为一“抽象方法”,一个含有抽象方法的类必须定义成抽象类,也就是使用abstract关键字来定义类。

abstract 修饰符表示所定义的类可能含有一些没有定义具体实现的抽象成员,因此你不能构建抽象类的实例,如果你试图这么做,编译器将报错。
contents 方法本身没有使用 abstract 修饰符,一个没有定义实现的方法就是抽象方法,和 Java 不同的是,抽象方法不需要使用 abstract 修饰符来表示,只要这个方法没有具体实现,就是抽象方法,相反,如果该方法有具体实现,称为“具体(concrete)”方法。
如果在父类中,定义了field,但是没有给出初始值,则此field为抽象field;

扩展类

前面定义的 Element 为抽象类,不能直接用来创建该类的对象,因此我们需要创建 Element 的子类。这些子类需要实现 Element 类定义的抽象函数。

class ArrayElement(conts: Array[String]) extends Element {
  def contents: Array[String] = conts
}

extends 具有两个功效,一是让 ArrayElement 继承所有 Element 类的非私有成员,第二使得 ArrayElement 成为 Element 的一个子类。而 Elemen t称为 ArrayElement 的父类。

override 和 super 关键字

Scala中,如果子类要覆盖父类中的一个非抽象方法,必须要使用 override 关键字;子类可以覆盖父类的 val 修饰的field,只要在子类中使用 override 关键字即可。
override 关键字可以帮助开发者尽早的发现代码中的错误,帮助编译器发现一些难以发现的错误,可以增强系统安全进化,比如, override 修饰的父类方法的方法名拼写错误。
此外,在子类覆盖父类方法后,如果在子类中要调用父类中被覆盖的方法,则必须要使用 super 关键字,显式的指出要调用的父类方法。
实现抽象成员无需使用 override,如果子类没有重载父类中的成员,不可以使用 override 修饰符。
override def getName = "your name is " + super.getName

调用父类的constructor

Scala中,每个类都可以有一个主constructor和任意多个辅助constructor,而且每个辅助constructor的第一行都必须调用其他辅助constructor或者主constructor代码;
子类的辅助constructor是一定不可能直接调用父类的constructor的;只能在子类的主constructor中调用父类的constructor。
如果父类的构造函数已经定义过的 field,比如name和age,子类再使用时,就不要用 val 或 var 来修饰了,否则会被认为,子类要覆盖父类的field,且要求一定要使用 override 关键字。

class Person(val name:String,val age:Int){
  var score :Double=0.0
  var address:String="beijing"
  def this(name:String,score:Double)={
    //每个辅助constructor的第一行都必须调用其他辅助constructor或者主constructor代码
    //主constructor代码
      this(name,30)
      this.score=score
  }
  //其他辅助constructor
  def this(name:String,address:String)={
      this(name,100.0)
      this.address=address
  }
}
class Student(name:String,score:Double) extends Person(name,score)

final

在定义类的继承关系时,有时你不希望基类的某些成员被子类重载,和 Java 类似,在 Scala 中也是使用 final 来修饰类的成员。
如果你希望某个类不可以派生子类,则可以在类定义前加上 final修饰符

final class ArrayElement extends Element { 
   override def demo() { 
    println("ArrayElement's implementation invoked") 
  } 
} 

Scala 的类层次关系

在这里插入图片描述

由于所有的类都继承自 Any,因此 Scala 中的对象都可以使用==,!=,或 equals 来比较,使用##或 hashCode 给出 hash 值,使用 toString 转为字符串。Any 的==和!=定位为 fianl,因此不可以被子类重载。实际上和 equals 等价,!=和 equals 的否定形式等价,因此重载 equals 可以修改和!=的定义。

根类 Any 有两个子类:AnyVal 和 AnyRef。AnyVal 是 Scala 里每个内建值类型的父类。有九个这样的值类型:Byte,Short,Char,Int,Long,Float,Double,Boolean 和 Unit。其中的前八个对应到 Java 的基本数值类型,它们的值在运行时表示成 Java 的类型。Scala 里这些类的实例都写成字面量。例如,42 是 Int 的实例,’x’是 Char 的实例,false 是 Boolean 的实例。值类型都被定义为即是抽象的又是 final 的,你不能使用 new 创造这些类的实例。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值