I have made a very simple Scala program which just prints Hello World
:
object HelloWorldActivity {
def main(args: Array[String]) {
println("Hello, world")
}
}
To understand how Scala converts to Java bytecode I decompiled the resulting jar file where there are two files: HelloWorldActivity.class
and HelloWorldActivity$.class
.
The first one contains this code:
import scala.reflect.ScalaSignature;
@ScalaSignature(bytes="****************")
public final class HelloWorldActivity
{
public static void main(String[] paramArrayOfString)
{
HelloWorldActivity..MODULE$.main(paramArrayOfString);
}
}
while the second one contains:
import scala.Predef.;
public final class HelloWorldActivity$
{
public static final MODULE$;
static
{
new ();
}
public void main(String[] args)
{
Predef..MODULE$.println("Hello, world");
}
private HelloWorldActivity$()
{
MODULE$ = this;
}
}
what I can't understand is what the following does:
static
{
new ();
}
What's the reason to put an empty new ()
inside static
, and how does static
alone not throw a compile/run error?
If it helps I'm using http://gradle.org/docs/current/userguide/scala_plugin.html
and having this in build.gradle
:
apply plugin: 'scala'
repositories{
mavenCentral()
mavenLocal()
}
dependencies{
compile "org.scala-lang:scala-library:2.10.1"
}
The decompiler isn't producing valid Java code there.
Here's what javap -p -v 'HelloWorldActivity$'
shows:
public static {};
descriptor: ()V
flags: ACC_PUBLIC, ACC_STATIC
Code:
stack=1, locals=0, args_size=0
0: new #2 // class HelloWorldActivity$
3: invokespecial #12 // Method "<init>":()V
6: return
That's just creating a new instance of the class. So, the decompiler should have showed this code for the static initialiser:
static {
new HelloWorldActivity$();
}
The static initialiser is executed once when the class is first loaded. This would typically occur when the main method in HelloWorldActivity
is first executed, because that's where the code that uses HelloWorldActivity$
is.
Note that the static initialiser isn't storing the reference to the newly created instance. Instead, the constructor stores the reference to this
(i.e. the reference to the singleton instance) into the MODULE$
field.
private HelloWorldActivity$();
descriptor: ()V
flags: ACC_PRIVATE
Code:
stack=1, locals=1, args_size=1
0: aload_0
1: invokespecial #29 // Method java/lang/Object."<init>":()V
4: aload_0
5: putstatic #31 // Field MODULE$:LHelloWorldActivity$;
8: return
Or, as your decompiler correctly shows:
private HelloWorldActivity$() {
MODULE$ = this;
}
Edit: Regarding the static {…}
syntax for defining a static initialiser, see the Java Language Specification §8.7 Static Initializers for a reference.
It's also possible to write an instance initialiser, by writing a {…}
block in your class. Instance initialisers are executed when creating each instance of the class, in much the same way as field initialisation is performed.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With