Scala主要构造函数及其生成的字段/属性 [英] Scala primary constructors and the fields/properties they generate
问题描述
Scala的新手,无论我阅读了多少篇文章/教程(例如这些 | 三个 | 一个)我
New to Scala and no matter how many articles/tutorials I read (like these | three | ones) I can't seem to wrap my brain around how constructors work.
让我们在这里举三个主要构造函数的例子:
Let's take three examples of a primary constructor here:
// 1
class Fizz(buzz : Buzz) { ... }
// 2
class Fizz (val buzz : Buzz) { ... }
// 3
class Fizz (var buzz : Buzz) { ... }
对于以下每个选项:
- 是
buzz
属性已创建?
- 是否公开?
- 它可变吗?
- 是静态的吗?
- 是否为此创建了一个吸气剂/设置器?
- Is a
buzz
property created?- If so, is it public?
- Is it mutable?
- Is is static?
- Is a getter/setter created for it?
- 是否公开?
- 它可变吗?
- 是静态的吗?
- 是否为此创建了一个吸气剂/设置器?
- If so, is it public?
- Is it mutable?
- Is is static?
- Is a getter/setter created for it?
推荐答案
构造函数实际上是Scala中的野兽。实际上,Scala编译器能够为您做出一些明智的选择。
Constructors are actually a pretty wild beast in Scala. In fact the Scala compiler is able to make some smart choices for you.
根据您的问题的措辞,我认为您可能对Java有一定的经验。为了清楚地说明正在发生的事情-并允许您将来进行实验-让我们反编译Scala编译器生成的代码,以便我们可以看到Java的等效代码。为简洁起见,我只显示方法/字段的声明,而不显示它们的实现。
By the phrasing of your question, I take it you probably have some experience with Java. To make it perfectly clear what's happening - and allow you to experiment yourself in the future - let's decompile the code that the Scala compiler produces so we can see the Java equivalent. For conciseness, I'll only show the declarations of the methods/fields, and not their implementation.
class Fizz(buzz : Buzz)
将编译为Java的
public class Fizz { public Fizz(Buzz); }
因为
Fizz
不会除了声明构造方法本身之外,没有声明任何引用buzz
的方法/字段,Scala不会为其创建任何字段/方法。Since
Fizz
doesn't declare any method/field referencingbuzz
(apart from the constructor itself), Scala will not create any field/method for it.class Fizz(buzz : Buzz) { def foo: Buzz = buzz }
这一次
foo
方法使用了buzz
,因此编译器必须将其存储为字段。由于未将字段声明为var
,因此将其设为private final
。This time
buzz
is used by thefoo
method, and so the compiler has to store it as a field. Since the field was not declared avar
, it will be madeprivate final
.public class Fizz { private final Buzz buzz; public Buzz foo(); public Fizz(Buzz); }
val
限定符
val
qualifierclass Fizz(val buzz : Buzz)
这一次,您明确表示要让
嗡嗡声
成为val
。这将产生以下效果:创建一个private final
字段来保存buzz
,并使用相同的公共方法进行访问This time, you explicitly said you wanted
buzz
to be aval
. This will have the effect of creating aprivate final
field to holdbuzz
, and a public method of the same to access it.public class Fizz { private final Buzz buzz; public Buzz buzz(); public Fizz(Buzz); }
var
限定符
var
qualifierclass Fizz(var buzz : Buzz)
这种情况与上一个非常相似,只是现在您指定要修改
buzz
。这将导致Scala编译器以有趣的名称buzz_ $ eq
为您提供setter方法。$
shenanigan仅由于命名方法中的JVM约束而需要。在您的Scala代码中,此方法将显示为buzz _ =
,语法糖将允许您将其称为fizz.buzz = someBuzz
。这样,实际上看起来好像您是作为字段进行突变,但实际上您只是在调用设置器。This case is very similar to the previous one, except that now you're specifying that you want to be able to modify
buzz
. This will cause the Scala compiler to provide a setter method for you, under the funny name ofbuzz_$eq
. The$
shenanigan is only required because of JVM constraints in naming methods. In your Scala code, this method will appear asbuzz_=
and syntactic sugar will allow you to call it asfizz.buzz = someBuzz
. This way, it actually looks as if you're mutating as field, but you're really only calling a setter.public class Fizz { private Buzz buzz; public Buzz buzz(); public void buzz_$eq(Buzz); public Fizz(Buzz); }
如何反编译Scala?
在调查此类问题时,这些命令很有用:
How to decompile Scala?
These commands are helpful when investigating that kind of issue:
scalac Fizz.scala
将创建一个人类难以理解的编译后的
Fizz.class
。您可以使用will create a compiled
Fizz.class
that is not human-readable. You can decompile it into a Java version usingjavap -constants -p Fizz
而在包含
Fizz.class
这篇关于Scala主要构造函数及其生成的字段/属性的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!