131

Daily Kotlin: Static methods – AndroidPub

 6 years ago
source link: https://android.jlelse.eu/daily-kotlin-static-methods-9330552cde8a?gi=a2d0a19c28fc
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

Daily Kotlin: Static methods

If you come from Java world, you are already familiar of static methods. They prevent us from copying our methods to every class and allows using them without creating an object. But, what if I told you that we don’t have static methods in Kotlin?!

1*Gr557EcchFrxks4n9NuEWg.png

True. But that doesn’t mean that we can’t reap the benefits p\rovided by static methods in Kotlin. There is a way around them. Let’s see how.

The documentation of Kotlin recommends that you should use package-level functions if you want to follow DRY. This might seem a little odd if you have worked with Java because it’s not there in Java! Let’s create a package level function in Kotlin. All you need to do is create a file with .kt extension and put a method which you’ll be using at multiple places. I’ll be creating a file name SampleClass.kt The content of SampleClass.kt is:

package packageA
fun bar(){
println("Method bar")
}

As you can see, we didn’t have to put our bar() method under some top-level class declaration. If you look at the decompiled code, it looks like the below:

public final class SameClassKt {
public static final void bar() {
String var0 = "Method bar";
System.out.println(var0);
}
}

Even though we didn’t put it under any class declaration, Kotlin, on compilation, will create a class with name SampleClassKt and will place the method inside it. And notice what the signature of our method is: public static final void bar() Exactly what we wanted to have!

If you want to call this function from any other class, let’s say HelloWorld.kt, you can call it by doing:

package packageB
import packageA.bar
fun main(args: Array<String>) {
bar()
}

Notice that we have to import that method from its package, hence the import packageA.bar statement.

Another way to do this, is by putting the method in object declaration.

package packageA
object Foo{
fun bar() = println("Method bar")
var foo="foo"
}

And you can access it like:

Foo.bar()

The object declaration is mostly used inside a class, it is useful if you want to access the internals of the class. To understand it better, let’s see its decompiled code:

public final class Foo {
public static final Foo INSTANCE;

public final void bar() {
String var1 = "Method bar";
System.out.println(var1);
}

private Foo() {
INSTANCE = (Foo)this;
}

static {
new Foo();
}
}

Any methods or variable under object declaration will work as static method or variable.

If you look in the above code, we have a static block which will be executed when the class is loaded into the memory, this block is creating the Foo object. Notice that the constructor is private, so the object can only be created from inside the class. Rings a bell? This way we are getting a Singleton class!

1*PLd1cRsyeey4vYAKKxVeRA.gif

Source:Giphy

But, if you want to do it just like the old style Java, i.e. by using class name as a qualifier, you need companion identifier.

class SampleClass{
companion object {
fun bar()= print("Bar method")
}
}

And then, you can access it from Kotlin code using the same syntax as used in Java. i.e.

SampleClass.foo()

One thing to note is that, if you call the method under companion object from Java code, you’ll need to place Companion identifier between class name and method name. e.g.

SampleClass.Companion.foo();

If you don’t like to place Companion identifier in between, you can also give a name to your object

companion object Foo{
fun foo()= print("In foo method")
}

And then call it by SampleClass.Foo.foo().

If you want to get rid of Companion identifier, and also don’t want to give any name to your object, you need to place @JvmStatic annotation with the method name.

class SampleClass{
companion object {
@JvmStatic
fun foo()= print("In foo method")
}
}

Then you can call it like SampleClass.foo() from Java code also.

Before we close this topic, let’s see how to resolve extension functions statically. If you aren’t familiar with extension functions, simply put, they are methods defined outside the class but behaves as if they are member functions. Check below example:

fun main(args: Array<String>) {
val sampleClass=SampleClass()
sampleClass.foo()
}
class SampleClass{
}
private fun SampleClass.foo() {
println("saas")
}

As you can see, we accessed foo() method as if it was a part of SampleClass.

Anyways, now, we will try to access the extension functions statically. To do so, we need to put an empty companion object inside the class.

class SampleClass{
companion object
}

To define an extension function that can be called statically, we need to put Companion identifier between the receiver class and method name:

private fun SampleClass.Companion.foo() {
println("saas")
}

Now, we can call the extension function without creating an object of the receiver class:

SampleClass.foo()

If you look at the decompiled code, it’s pretty much what we wanted:

private static final void foo(@NotNull SampleClass.Companion $receiver) {
String var1 = "saas";
System.out.println(var1);
}

Helpful links:

Documentation of Kotlin

Blog of JetBrains team discussing static constants in Kotlin.

Great thread by abreslavon resolving extension function statically.


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK