我是scala的新手,需要澄清下面涉及类的构造函数的代码片段。
class sample (a: Int, b: Int) {
/* define some member functions here */
}
我可以认为变量a
和b
是私有的sample
类吗?
class sample (val a: Int, val b: Int) {
/* define some member functions here */
}
在这种情况下,a
和b
可以公开访问吗?在参数列表中为构造函数添加val
关键字的确切效果是什么?如果我使用def
关键字而不是val
,它是否也具有相同的效果?
答案 0 :(得分:7)
class sample (a: Int, b: Int)
在这种情况下,a和b是私有的。用javap反汇编表明a和b不是类的一部分(Scala称这些类字段):
public class Sample extends java.lang.Object implements scala.ScalaObject{
public Sample(int, int);
}
a和b以val开头。使用javap进行反汇编显示a和b现在是Sample中的公共字段。
class sample (val a: Int, val b: Int)
public class Sample extends java.lang.Object implements scala.ScalaObject{
public int a();
public int b();
public Sample(int, int);
}
在构造函数中使用def
而不是val
,它将无法编译。 def
用于定义函数。不确定是否可以在构造函数中使用def
作为参数。
另外,请注意私有和受保护的行为与您期望的一样。鉴于此:
class Sample(private val a: Int, protected val b: Int, val c: Int)
使用javap反汇编到以下内容:
public class Sample extends java.lang.Object implements scala.ScalaObject{
public int b();
public int c();
public Sample(int, int, int);
}
答案 1 :(得分:6)
以下Scala类显示构造函数参数的四种可能性(3种不同的声明,其中一种有两种效果):
class ConstructorParams (local:Int, prvt:Int, val readonly:Int, var writable:Int) {
def succ_prvt() = prvt + 1
}
local
未被任何方法引用。它仅作为构造函数中的局部变量存在(它可以由字段初始化者引用而不更改它;尝试将val foo = local
添加到构造函数中。)prvt
由方法引用,因此它变为私有字段。val
声明符创建一个getter和一个私有支持字段。var
声明符同时创建一个getter和setter,以及一个私有支持字段。特别要注意,没有val
或var
声明符的构造函数参数只有在类中的函数中引用时才是私有的(这是可访问性问题);否则,它是本地的(这是范围问题)。
从技术上讲,最后三个参数作为本地值和私有字段(初始化为本地值)存在,但这种区别不应该出现太多,所以你可以把它放在脑海中。
def
作为参数声明符没有多大意义,因为它用于引入新函数,而不是声明值/变量名称;它也不用于函数参数(构造函数参数与函数参数密切相关)。由于函数是第一类,因此使用函数类型而不是特殊声明符来声明参数包含函数。
通过将ConstructorParams
传递给编译器,打印出编译器对-Xprint:constructors
所做的事情,我们得到(添加了注释):
class ConstructorParams extends Object {
/* 2nd (no-declarator) param becomes private field due to reference in `succ_prvt()` */
<paramaccessor> private[this] val prvt: Int = _;
/* `val` becomes private field + getter */
<paramaccessor> private[this] val readonly: Int = _;
<stable> <accessor> <paramaccessor> def readonly(): Int = ConstructorParams.this.readonly;
/* `var` becomes private field + getter + setter */
<paramaccessor> private[this] var writable: Int = _;
<accessor> <paramaccessor> def writable(): Int = ConstructorParams.this.writable;
<accessor> <paramaccessor> def writable_=(x$1: Int): Unit = ConstructorParams.this.writable = x$1;
/* causes `prvt` constructor param to become private field */
def succ_prvt(): Int = ConstructorParams.this.prvt.+(1);
def <init>(local: Int, prvt: Int, readonly: Int, writable: Int): ConstructorParams = {
ConstructorParams.this.prvt = prvt;
ConstructorParams.this.readonly = readonly;
ConstructorParams.this.writable = writable;
ConstructorParams.super.<init>();
()
}
}
上面的示例类编译为Java等价物:
public class ConstructorParams {
/* 2nd (no-declarator) param becomes private field due to reference in `succ_prvt()` */
private final int prvt;
public int succ_prvt() {
return this.prvt + 1;
}
/* `val` becomes private field + getter */
private final int readonly;
public int readonly() { return this.readonly; }
/* `var` becomes private field + getter + setter */
private int writable;
public int writable() { return this.writable; }
public void writable_$eq(int x$1) {
this.writable = x$1;
}
/* 1st param is local, since it's not referenced in any other methods */
public ConstructorParams(int local, int prvt, int readonly, int writable) {
/* parent constructor is invoked implicitly, so not repeated here */
this.prvt = prvt;
this.readonly = readonly;
this.writable = writable;
}
}
如果您使用javap
参数在ConstructorParams(如Brian所做的)上使用-p
,您将看到与上述Java源代码中的类签名等效的类签名。