Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What does "new ()" do inside "static" and how does "static" alone not throw a compile/run error?

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"
}
like image 558
Alper Turan Avatar asked Apr 18 '15 20:04

Alper Turan


1 Answers

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.

like image 183
Martin Ellis Avatar answered Nov 14 '22 23:11

Martin Ellis