10.Scala-继承

第10章 继承

10.1 继承类

和 Java 一样使用 extends 关键字,在定义中给出子类需要而超类没有的
字段和方法,或者重写超类的方法。
class Person {
  var name = ""
}
class Employee extends Person {   var salary = 0.0   def description = "An employee with name " + name + " and salary " + salary }

 提示:

如果类声明为 final,他讲不能被继承。如果单个方法声明为 final,将不
能被重写。

 

 

 

 

 

10.2 重写方法

重写一个非抽象方法需要用 override 修饰符。
调用超类的方法使用 super 关键字
class Person {
  var name = ""
  override def toString = getClass.getName + "[name=" + name + "]"
}



class Employee extends Person {   var salary = 0.0   override def toString = super.toString + "[salary=" + salary + "]" }

 

 

 

 

 

10.3 类型检查和转换

 

要测试某个对象是否属于某个给定的类,可以用 isInstanceOf 方法。用
asInstanceOf 方法将引用转换为子类的引用。classof 获取对象的类名。

1)classOf[String] 就如同 Java 得 String.class

2)obj.isInstanceOf[T] 就如同 Java 的 Obj isInstanceof T

3)obj.asInstanceOf[T] 就如同 Java 的 (T)Obj

println("Hello".isInstanceOf[String])
println("Hello".asInstanceOf[String])
println(classOf[String])

 

 

 

 

 

 

10.4 受保护的字段和方法

 protected 在 Scala 中比 Java 要更严格一点,即,只有继承关系才可以访问,同一个包下时不可以的。

 

 

 

 

10.5 超类的构造

类有一个主构造器和任意数量的辅助构造器,而每个辅助构造器都必须以对先前定义的辅助构造器

或主构造器的调用开始。子类的辅助构造器最终都会调用著构造器,只有主构造器可以调用超类的

构造器。辅助构造器永远都不可能直接调用超类的构造器。在Scala的构造器中,你不能调用 super(params). 

 

** 当前类的【辅助构造器】,最终都会调用当前类的【主构造器】

** 子类的主构造器,最终都会调用父类的构造器(可以是辅助构造器,可以是主构造器)

 

class Dog(age: Int){
  def this(){
    this(10)
  }
} val dog
= new Dog(20) val dog = new Dog()

 

 

 

class Person(val name: String, val age: Int) {
  override def toString = getClass.getName + "[name=" + name + ",age=" + age + "]"
}

class Employee(name: String, age: Int, val salary : Double) extends Person(name, age) {   override def toString = super.toString + "[salary=" + salary + "]" }

 

 

 

 

 

 

10.6 重写字段(覆写字段)

子类改写父类或者抽象父类的字段,通过以下方式: 

 

class Person1(val name: String, var age: Int) {
  
  println("主构造器已经被调用")
  val school = "五道口职业技术学院"
  def sleep = "8 hours"

  override def toString: String = "我的学校是:" + school + ",我的名字:" + name + ",我的年龄:" + age
}


class Person2(name: String, age: Int) extends Person1(name, age){
override val school: String = "清华大学"
}
 

 

调用:

//覆写字段
val person = new Person2("nick", 20)
println(person) 
    //主构造器已经被调用
    //我的学校是:清华大学,我的名字:nick,我的年龄:20

 

 

 尖叫提示:

1、def 只能重写另一个 def

2、val 只能重写另一个 val 或不带参数的 def 不能重写 var

3、var 只能重写一个抽象的 var

val a = "123" //不能被 def 重写
def a = "123" //不带参数的 def 可以被 val 重写

 

 

 

什么是抽象 var?

sbstract class Person3{
  var name: String //这就是一个抽象的var
}

 

 

 

 

 

 

10.7 匿名子类

和 Java 一样,你可以通过包含带有定义或重写的代码块的方式创建一个
匿名的子类:
class Person(val name: String) {
  override def toString = getClass.getName + "[name=" + name + "]"
}


使用: val alien
= new Person("Fred") {   def greeting = "Greetings, Earthling! My name is Fred." }

println(alien.greeting)

 

 

 

 

 

 

 

10.8 抽象类

可以通过 abstract 关键字标记不能被实例化的类。方法不用标记
abstract,只要省掉方法体即可。抽象类可以拥有抽象字段,抽象字段就是没有初始值的字段。 
abstract class Person(val pname: String) {
  val id: Int
  // No initializer—this is an abstract field with an abstract getter method
  var name: String
  // Another abstract field, with abstract getter and setter methods
  def idString: Int // No method body—this is an abstract method
}

class Employee(pname: String) extends Person(pname) {   val id = 5;   var name = ">>>"   def idString = pname.hashCode // override keyword not required }

 

子类实现抽象方法可以省略(不建议) override。

 

 

 

 

 

 

 

 

10.9 构造顺序和提前定义

当子类重写了父类的方法或者字段后,父类又依赖这些字段或者方法初始化,这个时候就会出现问题,
比如:
class Creature {
  val range: Int = 10
  val env: Array[Int] = new Array[Int](range)
}



class Ant extends Creature {   override val range = 2 }

 

构造顺序:
1) Ant 的构造器在做它自己的构造之前,调用 Creature 的构造器
2) Creature 的构造器将它的 range 字段设为 10
3) Creature 的构造器为了初始化 env 数组,调用 range()取值器
4) 该方法被重写以输出(还未初始化的)Ant 类的 range 字段值
5) range 方法返回 0,(这是对象被分配空间时所有整形字段的初始值)
6) env 被设为长度为 0 的数组。
7) Ant 构造器继续执行,将其 range 字段设为 2.
那么 env 的大小是多少?是 0,
 
解决这个问题,可以有 3 种方法:
1) 将 val 声明为 final,这样子类不可改写。
2) 将超类中将 val 声明为 lazy,这样安全但并不高效
3) 可以使用提前定义语法,可以在超类的构造器执行之前初始化子类的 val 字段,
class Ant2 extends {
  override val range = 3
} with Creature

 

 

笔记:

class Creature {
  val range: Int = 10
  val env: Array[Int] = new Array[Int](range)
}



class Ant extends Creature {
  override val range = 20
}

class Ant2 extends {
  override val range = 20
} with Creature



调用:
val ant = new Ant
println(ant.range) //20
println(ant.env.length) //0


val ant2 = new Ant2
println(ant2.range) //20
println(ant2.env.length) //20

 

 

 

 

 

 

10.10 Scala 继承层级

 

在scala中,所有其他类都是AnyRef的子类,类似Java的Object。
AnyVal和AnyRef都扩展自Any类。Any类是跟节点
Any中定义了isInstanceOf、asInstanceOf方法,以及哈希方法等。
Null类型的唯一实例就是null对象。可以将null赋值给任何引用(AnyRef),但不能赋值给值类型(AnyVal)的变量。
Nothing类型没有实例。它对于泛型结构是有用处的,举例:空列表Nil的类型是List[Nothing],它是List[T]的子类型,T可以是任何类。

::Nil 这是产生一个新的集合,不是在原有基础上追加

 

 

 

 

 

 

 

 

posted @ 2019-07-03 20:46  LXL_1  阅读(195)  评论(0)    收藏  举报