我在扩展App
的对象中遇到了一些bizzar行为。看看以下REPL命令:
scala> object A extends App {val x = "I am null"}
defined module A
scala> object B {val x = "I am a string"}
defined module B
scala> A.x
res0: java.lang.String = null
scala> B.x
res1: java.lang.String = I am a string
好吧,这有点奇怪......但它更奇怪了。然后我认为object
中的val进行了一些懒惰的评估...所以我尝试了一个真正的lazy val
:
scala> object C extends App {lazy val x = "What am I?"}
defined module C
scala> C.x
res2: java.lang.String = What am I?
那么这里发生了什么?为什么常规val获得空值?
当我使用lazy val
时,为什么这种行为会发生变化?
App
特性有什么特别之处,使得常规值不被评估?
答案 0 :(得分:9)
App扩展DelayedInit特质。因此所有语句和所有值定义都会移至delayedInit
方法。 Lazy val可以工作,因为它编译为方法。
例如,如果您反编译此类:
class TestApp extends App{
val test = "I am null"
lazy val testLazy ="I am a string"
}
你将使用'懒惰方法'来上课:
public String testLazy()
{
if((bitmap$0 & 1) == 0)
synchronized(this)
{
if((bitmap$0 & 1) == 0)
{
testLazy = "I am a string";
bitmap$0 = bitmap$0 | 1;
}
BoxedUnit _tmp = BoxedUnit.UNIT;
}
return testLazy;
}
内部类delayedInit.body
中的和delayedInit方法:
public final class delayedInit.body extends AbstractFunction0
implements ScalaObject
{
public final Object apply()
{
$outer.test_$eq("I am null");
return BoxedUnit.UNIT;
}
private final TestApp $outer;
....
只有在调用delayedInit时,才会将值“我为空”分配给test
字段。