• 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 这是产生一个新的集合,不是在原有基础上追加

     

  • 相关阅读:
    打印杨辉三角(直角) 练习
    数组 for 练习
    数组排序 (转)
    java如何获取从键盘输入多个数字,并计算平均数 (转)
    Eclipse快捷键 (转) 待续
    输入首字母判断周几(有瑕疵) 练习
    在java中如何用键盘输入一个数,字符,字符串 (转)
    Java中获取键盘输入值的三种方法 (转)
    Java 位运算(移位、位与、或、异或、非) (转)
    3.4 编程式路由
  • 原文地址:https://www.cnblogs.com/LXL616/p/11128960.html
Copyright © 2020-2023  润新知