2

I have a class A in java and interface B in Kotlin.

// kotlin
interface B {
    fun optional()
}
// java
class A implements B {
}

I want to write the default method (Java 8 feature) in Kotlin interface (B) and want to implement it in the class A. How can I achieve it?

Thanks in advance.

Ilya
  • 21,871
  • 8
  • 73
  • 92
Ajinkya S
  • 570
  • 7
  • 17
  • if you already implement it in the class, why add it as a default method? that makes no sense. – Stultuske Nov 06 '19 at 11:36
  • There is no `default` keyword in Kotlin, you can just provide a method body which will be the default then. – deHaar Nov 06 '19 at 11:37
  • `default` methods are meant to be *implemented* within the interface..which further could be overridden though. – Naman Nov 06 '19 at 11:38
  • @Naman yes, but not just like that. They are not really meant to add to new interfaces, they are meant to add new functionalities to old interfaces, without breaking backwards compatibility. – Stultuske Nov 06 '19 at 12:12

2 Answers2

5

In Kotlin, interface methods with bodies are by default compiled as following:

// kotlin
interface B {
    fun optional() { println("B optional body") }
}

is compiled roughly to:

public interface B {
   void optional();
   public static final class DefaultImpls {
      public static void optional(B $this) {
         System.out.println("B optional body");
      }
   }
}

Then, in Kotlin classes implementing this interface, the compiler adds an override for optional method automatically and calls B.DefaultImpls.optional(this) there.

public final class KA implements B {
   public void optional() {
      B.DefaultImpls.optional(this);
   }
}

But what if you want to implement this interface in Java and avoid having to override optional method and calling B.DefaultImpls manually? In that case you can use the experimental @JvmDefault feature.

First, you need to enable a couple of compiler options:

  • JVM target bytecode version 1.8 or higher: -jvm-target 1.8
  • enable JVM default methods: -Xjvm-default=enable (see the other available option values by the link above)

Then, you annotate optional method with @JvmDefault annotation:

// kotlin
interface B {
    @JvmDefault
    fun optional() { println("B optional body") }
}

and it becomes compiled to

public interface B {
   @JvmDefault
   default void optional() {
      System.out.println("B optional body");
   }
}

And now the Java implementation of this interface becomes just:

public final class A implements B {
}
Ilya
  • 21,871
  • 8
  • 73
  • 92
  • May I know where to add enable this JVM default methods:-Xjvm-default=enable – sharma.mahesh369 Feb 07 '20 at 06:43
  • @sharma.mahesh This is a command line option that you should pass to the compiler. In Gradle, this can be done by adding it to `kotlinOptions.freeCompilerArgs` list. For Android examples of specifying `kotlinOptions` see this question and its answers https://stackoverflow.com/questions/44141076/compilekotlin-block-in-build-gradle-file-throws-error-could-not-find-method-com – Ilya Feb 08 '20 at 08:07
1

As long as there are other classes than A implementing B, this may make sense. Otherwise you either don't need a default implementation or you don't have to implement that method in the implementing class.

However, you can do it like this:

interface B {
    fun optional() { print("optional") }
}

class A implements B {
    override fun optional() { print("B's optional") }
}
Ilya
  • 21,871
  • 8
  • 73
  • 92
deHaar
  • 17,687
  • 10
  • 38
  • 51