Scala子类实例访问父类字段报错,正确实现方式是什么?
问题分析与解决方案
嘿,我来帮你解决这个Scala子类访问父类字段的问题~
为什么会出现编译错误?
你遇到的错误super may not be used on variable age,核心原因是:
- Scala中var类型的成员不能通过
super关键字访问。var是可变变量,子类继承父类的var后,拿到的是同一个变量的引用——你在Cat类里写age=4,本质是直接修改了从Animal继承来的那个age变量的值,而不是定义了一个子类自己的age字段。此时父类的age和子类的age是同一个东西,不存在“父类的age值”(已经被改成4了)。 super关键字的设计目的是访问被子类重写的val或def成员,对于var这种只能被赋值、不能被override的成员,Scala不允许用super来访问。
正确的实现方式
根据你的需求,分两种场景给出解决方案:
场景1:想同时保留父类和子类的字段值
如果你希望子类有自己的age值,同时能访问父类的初始age值,需要把父类的age改成val,然后子类通过override重写它,这样就能用super访问父类的val了:
object MyClass { def main(args: Array[String]) { val dog=new Dog("s") dog.sayHello println(dog) val cat =new Cat("nancy") cat.sayHello println(cat) cat.superPrnt // 现在会输出父类的age=5 } abstract class Animal() { val greeting:String="boo" val age:Int=5 // 把var改成val def sayHello{println(greeting)} override def toString=s"I say $greeting and i am $age years old" } class Dog(name:String) extends Animal { override val greeting="woof" override val age=2 // override父类的val } class Cat(name:String) extends Animal{ override val greeting="meow" override val age=4 // override父类的val def superPrnt{println(super.age)} // 可以正常访问父类的age了 } }
运行这段代码,cat.superPrnt会输出5,而cat.age的值是4,两者互不干扰。
场景2:只是想修改继承的var值,需要保存父类初始值
如果你不想把父类的age改成val,只是想获取父类的初始值(比如5),可以在子类构造时先保存这个值,再修改age:
object MyClass { def main(args: Array[String]) { val dog=new Dog("s") dog.sayHello println(dog) val cat =new Cat("nancy") cat.sayHello println(cat) cat.superPrnt // 输出父类初始值5 } abstract class Animal() { val greeting:String="boo" var age:Int=5 def sayHello{println(greeting)} override def toString=s"I say $greeting and i am $age years old" } class Dog(name:String) extends Animal { override val greeting="woof" age=2 } class Cat(name:String) extends Animal{ override val greeting="meow" val parentAge = age // 在修改前保存父类的初始age值 age = 4 def superPrnt{println(parentAge)} // 输出保存的父类初始值 } }
这样cat.superPrnt会输出5,而cat.age是修改后的4。
补充说明
你的Dog类里age=2的写法是正确的,它直接修改了从Animal继承来的var变量,所以dog.age的值是2,父类的初始值5已经被覆盖了。
内容的提问来源于stack exchange,提问作者Gaurav Gupta
相关产品推荐
相关产品推荐

