Scala 构造函数中的最终变量

发布于 2024-12-07 18:12:34 字数 1108 浏览 2 评论 0原文

我对 Scala 还很陌生,但我知道你可以定义在构造函数中初始化的类变量,就像

class AClass(aVal: String)

在 java 中执行以下操作一样

class AClass {
    private String aVal;

    public AClass(String aVal) {
        this.aVal = aVal;
    }
}

。在 Java 中,我会将 aVal 声明为 Final。有没有办法在 Scala 语法中使 aVal 变量成为最终变量?

编辑:这是我编译以下 Scala 类时看到的内容:

class AClass(aVal: String) {
  def printVal() {
    println(aVal)
  }
}

我运行了 javap -private 并得到了输出

public class AClass extends java.lang.Object implements scala.ScalaObject{
  private final java.lang.String aVal;
  public void printVal();
  public AClass(java.lang.String);
}

当我将 scala 类定义更改为具有 class AClass(**val ** aVal: String) 我从 javap -private 得到以下输出

public class AClass extends java.lang.Object implements scala.ScalaObject{
  private final java.lang.String aVal;
  public java.lang.String aVal();
  public void printVal();
  public AClass(java.lang.String);
}

生成了公共方法 aVal 。我仍然在这里学习 - 谁能解释为什么会生成它?

注意我使用的是 scala 2.9

I'm still pretty new to Scala, but I know you can define class variables that are initialized in the constructor like

class AClass(aVal: String)

which would be like doing the following in java

class AClass {
    private String aVal;

    public AClass(String aVal) {
        this.aVal = aVal;
    }
}

In Java, I would declare aVal as final. Is there a way to make the aVal variable final in the Scala syntax?

EDIT: Here is what I am seeing when I compile the following Scala class:

class AClass(aVal: String) {
  def printVal() {
    println(aVal)
  }
}

I ran javap -private and got the output

public class AClass extends java.lang.Object implements scala.ScalaObject{
  private final java.lang.String aVal;
  public void printVal();
  public AClass(java.lang.String);
}

When I change the scala class definition to have class AClass(**val** aVal: String) I get the following output from javap -private

public class AClass extends java.lang.Object implements scala.ScalaObject{
  private final java.lang.String aVal;
  public java.lang.String aVal();
  public void printVal();
  public AClass(java.lang.String);
}

The public method aVal is generated. I'm still learning here - can anyone explain why that is generated?

Note I am using scala 2.9

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

小清晰的声音 2024-12-14 18:12:34
class AClass(aVal: String)

在此代码中,aVal 是最终变量。所以你已经有了一个最终变量。

class AClass(val aVal: String)

在此代码中,aVal 是最终的,并且您有 aVAl 的 getter。所以你可以像下面一样使用它

scala> val a= new AClass("aa")
a: A1 = A1@1d7d58f

scala> a.aVal
res2: String = aa

最后,

class AClass(var aVal: String)

在这段代码中,aVal不是最终的,你有aVal的getter和setter。所以你可以像下面这样使用它

scala> val a= new AClass("aa")
a: AClass = AClass@1c059f6

scala> a.aVal
res3: String = aa

scala> a.aVal = "bb"
a.aVal: String = bb

scala> a.aVal
res4: String = bb
class AClass(aVal: String)

In this code, aVal is a final variable. So You already have a final variable.

class AClass(val aVal: String)

In this code, aVal is final and you have getter of aVAl. So you can use it like below

scala> val a= new AClass("aa")
a: A1 = A1@1d7d58f

scala> a.aVal
res2: String = aa

And finally,

class AClass(var aVal: String)

In this code, aVal is not final and you have getter and setter of aVal. So you can use it like below

scala> val a= new AClass("aa")
a: AClass = AClass@1c059f6

scala> a.aVal
res3: String = aa

scala> a.aVal = "bb"
a.aVal: String = bb

scala> a.aVal
res4: String = bb
萝莉病 2024-12-14 18:12:34

复制自我的答案:Scala Final 与 val 的并发可见性

术语 final 有两种含义:a) 对于 Scala 字段/方法和 Java 方法,它意味着“不能在subclass”和 b) 对于 Java 字段和 JVM 字节码来说,这意味着“该字段必须在构造函数中初始化并且不能重新分配”。

val 标记的类参数(或者等效地,没有修饰符的情况类参数)在第二种意义上确实是最终的,因此是线程安全的。

证明如下:

scala>  class A(val a: Any); class B(final val b: Any); class C(var c: Any)
defined class A
defined class B
defined class C

scala> import java.lang.reflect._
import java.lang.reflect._

scala> def isFinal(cls: Class[_], fieldName: String) = {
     |   val f = cls.getDeclaredFields.find(_.getName == fieldName).get
     |   val mods = f.getModifiers
     |   Modifier.isFinal(mods)
     | }
isFinal: (cls: Class[_], fieldName: String)Boolean

scala> isFinal(classOf[A], "a")
res32: Boolean = true

scala> isFinal(classOf[B], "b")
res33: Boolean = true

scala> isFinal(classOf[C], "c")
res34: Boolean = false

或者使用 javap,可以方便地从 REPL 运行:

scala> class A(val a: Any)
defined class A

scala> :javap -private A
Compiled from "<console>"
public class A extends java.lang.Object implements scala.ScalaObject{
    private final java.lang.Object a;
    public java.lang.Object a();
    public A(java.lang.Object);
}

如果非 case 类的类参数未标记为 valvar,并且它不被任何方法引用,它只需要对类的构造函数可见。然后,Scala 编译器可以自由地优化远离字节码的字段。在 Scala 2.9.1 中,这似乎有效:

scala> class A(a: Any)
defined class A

scala> :javap -private A
Compiled from "<console>"
public class A extends java.lang.Object implements scala.ScalaObject{
    public A(java.lang.Object);
}

Copied from my answer: Scala final vs val for concurrency visibility

There are two meanings of the term final: a) for Scala fields/methods and Java methods it means "cannot be overridded in a subclass" and b) for Java fields and in JVM bytecode it means "the field must be initialized in the constructor and cannot be reassigned".

Class parameters marked with val (or, equivalently, case class parameters without a modifier) are indeed final in second sense, and hence thread safe.

Here's proof:

scala>  class A(val a: Any); class B(final val b: Any); class C(var c: Any)
defined class A
defined class B
defined class C

scala> import java.lang.reflect._
import java.lang.reflect._

scala> def isFinal(cls: Class[_], fieldName: String) = {
     |   val f = cls.getDeclaredFields.find(_.getName == fieldName).get
     |   val mods = f.getModifiers
     |   Modifier.isFinal(mods)
     | }
isFinal: (cls: Class[_], fieldName: String)Boolean

scala> isFinal(classOf[A], "a")
res32: Boolean = true

scala> isFinal(classOf[B], "b")
res33: Boolean = true

scala> isFinal(classOf[C], "c")
res34: Boolean = false

Or with javap, which can be conveniently run from the REPL:

scala> class A(val a: Any)
defined class A

scala> :javap -private A
Compiled from "<console>"
public class A extends java.lang.Object implements scala.ScalaObject{
    private final java.lang.Object a;
    public java.lang.Object a();
    public A(java.lang.Object);
}

If the class parameter of a non-case class is not marked as a val or var, and it is not referred to from any methods, it need only be visible to the constructor of the class. The Scala compiler is then free to optimize the field away from the bytecode. In Scala 2.9.1, this appears to work:

scala> class A(a: Any)
defined class A

scala> :javap -private A
Compiled from "<console>"
public class A extends java.lang.Object implements scala.ScalaObject{
    public A(java.lang.Object);
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文