Using Singletons and Companion Objects from Java

Scala compiles singleton and companion objects into a “singleton class” with a special $ symbol at the end of its name. Scala, however, treats a singleton and a companion object differently, as you’ll soon see.

When compiled, a Scala singleton turns into a Java class with static methods at the bytecode level. In addition, another regular class with methods that forward calls to the singleton class is created. So, for example, this code defines a singleton object Single, and Scala creates two classes, Single$ and the forward class Single:

Intermixing/Single.scala
 
object​ Single {
 
def​ greet() { println(​"Hello from Single"​) }
 
}

We can use the singleton object from Java as we’d use any Java class with static methods, as shown here:

Intermixing/SingleUser.java
 
//Java code
 
public​ ​class​ SingleUser {
 
public​ ​static​ ​void​ main(​String​​[]​ args) {
 
Single.greet();
 
}
 
}

The output from the previous code is shown here:

 
Hello from Single

It gets a bit complicated if you’re dealing with a companion object instead of a singleton. If your object is a companion object to a class with the same name, Scala creates two classes: one for the class and one for its companion. For example, Scala will compile the following Buddy class and its companion down to two files named Buddy and Buddy$, respectively.

Intermixing/Buddy.scala
 
class​ Buddy {
 
def​ greet() { println(​"Hello from Buddy class"​) }
 
}
 
 
object​ Buddy {
 
def​ greet() { println(​"Hello from Buddy object"​) }
 
}

In the example, there are two methods named greet, one in the Buddy class and the other in its companion object. The equivalent of this is like having both an instance method and a static method with the same name in a Java class. Accessing the instance method is rather easy from Java, but reaching into the companion object takes some effort.

Accessing the companion class from Java is much like accessing it from Scala. In Scala we’d write, for example, new Buddy().greet(); the Java version is almost the same, except we’d have to add the obligatory semicolon to the end. On the other hand, the syntax for accessing the method in the companion object is quite different in the two languages. In Scala, we’d simply type Buddy.greet(), but from Java, well…take a look at line 5 in the following code:

Intermixing/BuddyUser.java
Line 1 
//Java code
public​ ​class​ BuddyUser {
public​ ​static​ ​void​ main(​String​​[]​ args) {
new​ Buddy().greet();
Buddy$.MODULE$.greet();
}
}

If that code hurts your head, please know it’s not your fault. You had to jump through some hoops there, first getting to the companion object Buddy$ and then referring to its static MODULE$ property, which holds a reference to the instance. Finally you invoke the greet method on that instance. Once again your buddy here is the javap tool, which you can use to dig into and reckon with the bytecode the compiler generated.

Let’s compile and run the Java code to see the output:

 
Hello from Buddy class
 
Hello from Buddy object

At first, scanning through the code to access the methods on a companion object may induce a feeling of vertigo. If that happens, sit down and take your eyes off the code for a minute. Take some time to dig into the bytecode details presented by the javap tool and try to reason by walking through the object references. Once you get the hang of it, you’ll have no problem mastering complex Scala APIs from Java code, if your project needs demands that.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.145.50.183