[转载] Scala继承与Java的区别

参考链接: Java中将final与继承一起使用

在之前的笔记Java静态属性和方法的继承问题中,通过具体的实验证明,在子类中重写父类的字段时并没有覆盖父类的字段,只是隐藏了父类的字段。而在scala中则不同,scala子类的同名字段会重写且覆盖父类的同名字段,这里做了个简单实验,并记录下来。 

Parent.scala 

class Parent {

  val normalStr: String = "Normal member of parent."

 

  def normalMethod() = {

    println("Normal method of parent.")

  }

定义了一个字段normalStr和一个方法normalMethod(),在Scala中,类的字段是由一个私有属性和对应的getter/setter方法组成的。 

Child.scala 

class Child extends Parent {

  override val normalStr: String = "Normal member of child."

 

  override def normalMethod() = {

    println("Normal method of child.")

  }

子类Child继承了父类Parent,并override父类的normalStr和normalMethod()。 

TestMain和Result 

object TestMain{

  def main(args: Array[String]) {

    val child: Child = new Child

    println(child.normalStr)

    child.normalMethod()

 

    //val child1:Parent = child.asInstanceOf[Parent]

    //采用Parent类型的变量指向创建的Child对象

    val child1:Parent = new Child

    println(child1.normalStr)

    child1.normalMethod()

  }

输出的结果如下: 

Normal member of child.

Normal method of child.

Normal member of child.

Normal method of child. 

从结果可以看出,子类重写并覆盖了父类的同名属性和方法 

Scala子类的构造顺序 

这里顺便记录下Scala子类的构造顺序,这里直接用书上给出的例子,以便后续查看: 

先写两个类,一个父类Creature.scala,一个子类Ant.scala: 

Creature 

class Creature {

    val range: Int = 10

    val env: Array[Int] = new Array[Int](range)

    def show(): Unit = {

       println(range)

    }

Ant 

class Ant extends Creature {

    override val range = 2

现在创建一个Ant的对象ant,那么ant.env.length的值是多少,凭第一感觉应该是10或者2,然而答案是0,接下来我写下ant创建的过程中构造器的运行顺序: 

首先调用父类Creature的构造器(父类的构造器先于子类的构造器被调用),所以首先把range设置为10。为了后续的说明这里说明下,类的字段是由一个私有属性和对应的getter和setter方法组成的,而子类在重写父类的同名字段时,对于val类型的属性子类重写了getter方法。接下来初始化env数组,所以需要调用range的getter方法,然而子类已经重写了getter方法,且子类并没初始化,所有的字段都是对象创建过程中,内存清零后的默认值,所以此时range的值为0。这也就解释了上述问题的疑问。接下来调用子类的构造器,range被设为2。 

所以在构造器中,对象的初始化不应该依赖于val的值,因为val的值对应的getter方法可能会被子类重写覆盖。解决办法有: 

将val声明为final。(简单高效,但是不够灵活)在超类中将val声明为lazy。(简单灵活,但是不够高效)还有种就是子类中使用提前定义语法。(这个就不介绍了) 

ant对象调用show()方法输出的则是子类range的值,即为2。而在Java中,则是父类的range的值:10。主要原因还是由于在Scala中,子类重写父类的属性或者方法,覆盖了父类的属性和方法,而在Java中,只有非静态的方法会被子类重写覆盖,而非静态/静态属性和静态方法都只是被隐藏了。 

主要参考:《快学Scala》

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值