Jens Klingenberg

Kotlin Companion Object

Posted on March 18, 2018  •  3 minutes  • 430 words
Table of contents

What is a Companion Object?

When you are new to Kotlin and you are familiar with Java, you may be wondering how you can create static methods and fields in Kotlin. Unlike Java, Kotlin doesn’t have a static keyword. Kotlin has the concept of a companion object.

How to create a Companion Object?

You create it inside of a class with the syntax “companion object{}
class Printer{

     companion object {
        val testString = "1"
 
        @JvmStatic
        fun print(message:String){
            println(message)
        }
    }
}

Now all functions and fields inside the companion object are used like they are “static”.

How to call it from Kotlin

To call the functions/fields from a companion object you use the class and call the functions/fields.
Printer.print("Hello World")

How to call it from Java

By default you call companion functions/fields like “KotlinClassName”.Companion."MethodName"
Printer.Companion.print("Hello");

But Kotlin has the @JvmStatic Annotation.

@JvmStatic 
fun print(message:String){
    println(message)
}

Functions and fields that are annotated, can be used from Java like they are usual static functions

Printer.print("Hello World")

How does it work on the JVM

You can use Intellij/Android Studio to see the bytecode that the Kotlin Compiler generates. You can find the menu entry under Tools->Kotlin->Show Kotlin Bytecode

When you click on Decompile you can see what the Java equivalent to your Kotlin class would look like.

@Metadata(
  mv = {1, 1, 9},
  bv = {1, 0, 2},
  k = 1,
  d1 = {"\u0000\f\n\u0002\u0018\u0002\n\u0002\u0010\u0000\n\u0002\b\u0003\u0018\u0000 \u00032\u00020\u0001:\u0001\u0003B\u0005¢\u0006\u0002\u0010\u0002¨\u0006\u0004"},
  d2 = {"Lstart/Printer;", "", "()V", "Companion", "production sources for module JKCompanionExample"}
)
public final class Printer {
  @NotNull
  private static final String testString = "1";
  public static final Printer.Companion Companion = new Printer.Companion((DefaultConstructorMarker)null);

  @JvmStatic
  public static final void print(@NotNull String message) {
    Companion.print(message);
  }

  @Metadata(
    mv = {1, 1, 9},
    bv = {1, 0, 2},
    k = 1,
    d1 = {"\u0000\u001c\n\u0002\u0018\u0002\n\u0002\u0010\u0000\n\u0002\b\u0002\n\u0002\u0010\u000e\n\u0002\b\u0003\n\u0002\u0010\u0002\n\u0002\b\u0002\b\u0086\u0003\u0018\u00002\u00020\u0001B\u0007\b\u0002¢\u0006\u0002\u0010\u0002J\u0010\u0010\u0007\u001a\u00020\b2\u0006\u0010\t\u001a\u00020\u0004H\u0007R\u0014\u0010\u0003\u001a\u00020\u0004X\u0086D¢\u0006\b\n\u0000\u001a\u0004\b\u0005\u0010\u0006¨\u0006\n"},
    d2 = {"Lstart/Printer$Companion;", "", "()V", "testString", "", "getTestString", "()Ljava/lang/String;", "print", "", "message", "production sources for module JKCompanionExample"}
  )
  public static final class Companion {
    @NotNull
    public final String getTestString() {
      return Printer.testString;
    }

    @JvmStatic
    public final void print(@NotNull String message) {
      Intrinsics.checkParameterIsNotNull(message, "message");
      System.out.println(message);
    }

    private Companion() {
    }

    // $FF: synthetic method
    public Companion(DefaultConstructorMarker $constructor_marker) {
      this();
    }
  }
}

As you can see a companion object is compiled to public static final class Companion inside the Printer class.

What else can you do with companion objects?

  1. Note: A Kotlin class can only have one companion object
  2. You can give a companion object a name
    companion object MyCompanion {}
  3. Inheritance and Interfaces
    A companion object can extend classes and implement interfaces. But you can not extend companion object because they are final classes.

References

https://kotlinlang.org/docs/reference/object-declarations.html
Let's connect: