我正在阅读" Scala for the Impatient"在8.10中有一个例子:
class Animal {
val range: Int = 10
val env: Array[Int] = new Array[Int](range)
}
class Ant extends Animal {
override val range: Int = 2
}
作者解释了为什么env最终成为一个空数组[Int]:
[..] 3.为了初始化env数组,Animal构造函数调用range()getter。
重写该方法以产生Ant类的(尚未初始化的)范围字段。
range方法返回0.(这是分配对象时所有整数字段的初始值。)
将env设置为长度为0的数组。
- Ant构造函数继续,将其范围字段设置为2。[..]
醇>
我不理解第4步,因此接下来的步骤也不清楚。 range()方法被2覆盖,那么为什么它不在第4步中设置范围?
是的,Doe是这样的吗?当覆盖val时,它会被取消初始化,并且包含这个被覆盖的gals的所有val也会被修改。这是对的吗?如果是,为什么def与here概述的行为不同。为什么在构造函数调用和val之后定义def?答案 0 :(得分:2)
在你的评论之后,我决定真正看看书中究竟写了什么。在阅读了解释后,我决定不能更清楚地表达它。所以相反,我建议看看完全脱落的代码,这本书在短篇小说中没有位置。
将其另存为Scala脚本:
class Animal {
val range: Int = 10
val env: Array[Int] = new Array[Int](range)
}
class Ant extends Animal {
override val range: Int = 2
}
val ant = new Ant
println(ant.range)
println(ant.env.size)
然后使用-print
- 选项运行它:
> scala -nc -print yourScript.scala
你应该看到这样的事情:
class anon$1$Animal extends Object {
private[this] val range: Int = _;
<stable> <accessor> def range(): Int = anon$1$Animal.this.range;
private[this] val env: Array[Int] = _;
<stable> <accessor> def env(): Array[Int] = anon$1$Animal.this.env;
<synthetic> <paramaccessor> <artifact> protected val $outer: <$anon: Object> = _;
<synthetic> <stable> <artifact> def $outer(): <$anon: Object> = anon$1$Animal.this.$outer;
def <init>($outer: <$anon: Object>): <$anon: Object> = {
if ($outer.eq(null))
throw null
else
anon$1$Animal.this.$outer = $outer;
anon$1$Animal.super.<init>();
anon$1$Animal.this.range = 10;
anon$1$Animal.this.env = new Array[Int](anon$1$Animal.this.range());
()
}
};
class anon$1$Ant extends <$anon: Object> {
private[this] val range: Int = _;
override <stable> <accessor> def range(): Int = anon$1$Ant.this.range;
<synthetic> <stable> <artifact> def $outer(): <$anon: Object> = anon$1$Ant.this.$outer;
def <init>($outer: <$anon: Object>): <$anon: anon$1$Animal> = {
anon$1$Ant.super.<init>($outer);
anon$1$Ant.this.range = 2;
()
}
}
这是令人厌恶的代码,因为编译器在编译的后期阶段会看到它。它有点难以阅读,但重要的是这些声明:
// in Animal:
private[this] val range: Int = _;
<stable> <accessor> def range(): Int = anon$1$Animal.this.range;
// in Ant:
private[this] val range: Int = _;
override <stable> <accessor> def range(): Int =
anon$1$Ant.this.range;
以及Animal
的初始化程序中的语句:
anon$1$Animal.this.env = new Array[Int](anon$1$Animal.this.range())
您可以在此处看到,实际上有两个不同的变量range
:一个是Animal.this.range
,另一个是Ant.this.range
。此外,在desugared代码中还有完全独立的def
也称为range
:这些是为val
s自动生成的getter。 / p>
第一个变量确实在Animal
中初始化并设置为10
:
anon$1$Animal.this.range = 10;
但是,这并不重要,因为env
是使用getter range()
进行初始化的,后者会被覆盖以返回Ant.this.range
。变量Ant.this.range
的值已分配2
一次,但 Animal
的初始化程序后已完成。在Animal
初始化期间,变量Ant.this.range
保留默认值0
,因此反直觉结果。
如果您稍微简化了这些代码,您将获得一个可编辑且可读的示例,其行为方式相同:
class Animal {
private[this] var _Animal_range: Int = 0
def range: Int = _Animal_range
_Animal_range = 10
val env: Array[Int] = new Array[Int](range)
}
class Ant extends Animal {
private[this] var _Ant_range: Int = 0
override def range: Int = _Ant_range
_Ant_range = 2
}
val ant = new Ant
println(ant.range)
println(ant.env.size)
在这里,同样的事情发生了:
_Animal_range
分配了默认值0 _Ant_range
分配了默认值0 Animal
基类开始初始化_Animal_range
初始化为值10 env
,请调用getter range
。它在Ant
- 类中被覆盖,并返回_Ant_range
,它仍为0 env
设置为空数组Animal
基类完成初始化Ant
开始初始化_Ant_range
设置为2
。这就是为什么两个代码段都打印2
和0
。
希望有所帮助。
答案 1 :(得分:1)
def
,但是val
被保留在内存中,所以在这种情况下,val
版本仍然设置为零,因为它尚未初始化,def
版本被调用,因此永远不会给出误导性的价值。
这只是因为这里的val
被重载而没有及时初始化,因为必须从继承层次结构的顶部开始初始化类并进行构建。如果env
是def
你也可以,因为在调用之前它不会被创建,到那时val
都将被初始化。当然,这样每次调用env
时都会得到不同的列表,因此您可能更喜欢使用lazy val
,它在第一次调用时初始化,但后来保持不变并保存在内存中