6

我是 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,它是否也具有相同的效果?

4

2 回答 2

8

以下 Scala 类显示了构造函数参数的四种可能性(3 种不同的声明,其中一种具有两种效果):

class ConstructorParams (local:Int, prvt:Int, val readonly:Int, var writable:Int) {
  def succ_prvt() = prvt + 1
}
  1. 第一个参数local没有被任何方法引用。它仅作为构造函数中的局部变量存在(字段初始化程序可以引用它而不更改它;尝试添加val foo = local到构造函数)。
  2. 第二个,prvt,被一个方法引用,所以它成为一个私有字段。
  3. 第三val个声明器创建一个 getter 和一个私有支持字段。
  4. 第四个的var声明器创建了一个 getter 和一个 setter,以及一个私有的支持字段。

特别要注意,没有valorvar声明符的构造函数参数是私有的(这是一个可访问性的问题),只有当它在类中的函数中被引用时;否则,它是本地的(这是范围问题)。

从技术上讲,最后三个参数作为本地值和私有字段(初始化为本地值)存在,但这种区别不应该出现太多,所以你基本上可以忘记它。

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 源代码中的类签名等效的类签名。

于 2014-10-27T21:25:38.710 回答
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);
}
于 2012-10-06T07:34:52.590 回答