具有抽象变量和子构造函数的抽象 class;斯卡拉
Abstract class with abstract variables and child constructors; Scala
我有一个摘要 class 由另一个 class 扩展。
object WhosebugTest extends App
{
new ChildFunction()
}
abstract class Function() {
val a: Double
val b: Double
println(a, b)
}
class ChildFunction() extends Function() {
val a = 0.02
val b = 0.2
}
当我实例化 ChildFunction
时,它会为 a
和 b
打印 0.0
。
这显然不是我想要的,甚至不是我期望的。
我发现解决此问题的唯一方法是在 ChildFunction
lazy val a = 0.02
中说明。
这是正确的解决方案吗?
使 val 惰性起作用是因为它移动了写入字段 0.02 的点。要了解发生了什么,请阅读以下代码,这是 scalac 为您的示例生成的 java 字节代码。
需要注意的是,字段a和b是存储在子对象上的,它们的值0.02和0.2是在调用父对象的构造函数后才写入的。但是,在写入字段之前,在父级的构造函数中调用了 println。因此你的问题。
使 vals 延迟工作是因为在调用 a() 或 b() 时,将调用初始化代码.. 即父 class 现在将调用子代码class 在子 class 上设置字段。
public abstract class Function implements scala.ScalaObject {
public abstract double a();
public abstract double b();
public Function(); // NB: calls a() and b() on the child class
Code:
0: aload_0
1: invokespecial #13 // Method java/lang/Object."<init>":()V
4: getstatic #19 // Field scala/Predef$.MODULE$:Lscala/Predef$;
7: new #21 // class scala/Tuple2$mcDD$sp
10: dup
11: aload_0
12: invokevirtual #25 // Method a:()D
15: aload_0
16: invokevirtual #27 // Method b:()D
19: invokespecial #30 // Method scala/Tuple2$mcDD$sp."<init>":(DD)V
22: invokevirtual #34 // Method scala/Predef$.println:(Ljava/lang/Object;)V
25: return
}
public class ChildFunction extends Function implements scala.ScalaObject {
public double a();
Code:
0: aload_0
1: getfield #12 // Field a:D
4: dreturn
public double b();
Code:
0: aload_0
1: getfield #14 // Field b:D
4: dreturn
public ChildFunction(); // NB invokes parent constructor BEFORE writing values to fields a and b.
Code:
0: aload_0
1: invokespecial #20 // Method Function."<init>":()V
4: aload_0
5: ldc2_w #21 // double 0.02d
8: putfield #12 // Field a:D
11: aload_0
12: ldc2_w #23 // double 0.2d
15: putfield #14 // Field b:D
18: return
}
您可以 'fix' 通过使用 defs 而不是 lazy val 来解决这个问题(如下例)。或者更好的是,删除 println 并仅调用 a() 和 b() after ChildFunction 已完全构建。
object WhosebugTest extends App
{
new ChildFunction()
}
abstract class Function() {
def a: Double
def b: Double
println(a, b)
}
class ChildFunction() extends Function() {
override def a = 0.02
override def b = 0.2
}
我有一个摘要 class 由另一个 class 扩展。
object WhosebugTest extends App
{
new ChildFunction()
}
abstract class Function() {
val a: Double
val b: Double
println(a, b)
}
class ChildFunction() extends Function() {
val a = 0.02
val b = 0.2
}
当我实例化 ChildFunction
时,它会为 a
和 b
打印 0.0
。
这显然不是我想要的,甚至不是我期望的。
我发现解决此问题的唯一方法是在 ChildFunction
lazy val a = 0.02
中说明。
这是正确的解决方案吗?
使 val 惰性起作用是因为它移动了写入字段 0.02 的点。要了解发生了什么,请阅读以下代码,这是 scalac 为您的示例生成的 java 字节代码。
需要注意的是,字段a和b是存储在子对象上的,它们的值0.02和0.2是在调用父对象的构造函数后才写入的。但是,在写入字段之前,在父级的构造函数中调用了 println。因此你的问题。
使 vals 延迟工作是因为在调用 a() 或 b() 时,将调用初始化代码.. 即父 class 现在将调用子代码class 在子 class 上设置字段。
public abstract class Function implements scala.ScalaObject {
public abstract double a();
public abstract double b();
public Function(); // NB: calls a() and b() on the child class
Code:
0: aload_0
1: invokespecial #13 // Method java/lang/Object."<init>":()V
4: getstatic #19 // Field scala/Predef$.MODULE$:Lscala/Predef$;
7: new #21 // class scala/Tuple2$mcDD$sp
10: dup
11: aload_0
12: invokevirtual #25 // Method a:()D
15: aload_0
16: invokevirtual #27 // Method b:()D
19: invokespecial #30 // Method scala/Tuple2$mcDD$sp."<init>":(DD)V
22: invokevirtual #34 // Method scala/Predef$.println:(Ljava/lang/Object;)V
25: return
}
public class ChildFunction extends Function implements scala.ScalaObject {
public double a();
Code:
0: aload_0
1: getfield #12 // Field a:D
4: dreturn
public double b();
Code:
0: aload_0
1: getfield #14 // Field b:D
4: dreturn
public ChildFunction(); // NB invokes parent constructor BEFORE writing values to fields a and b.
Code:
0: aload_0
1: invokespecial #20 // Method Function."<init>":()V
4: aload_0
5: ldc2_w #21 // double 0.02d
8: putfield #12 // Field a:D
11: aload_0
12: ldc2_w #23 // double 0.2d
15: putfield #14 // Field b:D
18: return
}
您可以 'fix' 通过使用 defs 而不是 lazy val 来解决这个问题(如下例)。或者更好的是,删除 println 并仅调用 a() 和 b() after ChildFunction 已完全构建。
object WhosebugTest extends App
{
new ChildFunction()
}
abstract class Function() {
def a: Double
def b: Double
println(a, b)
}
class ChildFunction() extends Function() {
override def a = 0.02
override def b = 0.2
}