Skip to content

This is a small public project containing all the examples given in the Kotlin-Java interoperability presentation.

Notifications You must be signed in to change notification settings

danielgongora0204/kotlin-java-interoperability

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

6 Commits
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Kotlin-Java Interoperability

This is a small public project containing all the examples given in the Kotlin-Java interoperability presentation.

Based on

Little information on the JVM

Java Virtual Machine: It is a virtual machine designed to run applications, created with the "write once, run anywhere" mentality.

Running on the JVM involves the following steps:

  1. Compilation to Java Byte Code (AOT): First, the Java or Kotlin compiler (javac, kotlinc) compiles the code into an intermediate form known as Java Bytecode. This bytecode is a set of platform-independent instructions that can be executed by the JVM.

  2. Class Loader: The JVM uses a class loader to load the compiled bytecode (.class files) into memory. The class loader is responsible for finding and loading these classes into the JVM.

  3. Bytecode Verification: Before execution, the JVM verifies the bytecode to ensure it is valid and does not violate Java's security constraints. This step helps prevent malicious code from causing harm.

  4. Just-In-Time Compilation (JIT): The JVM includes a Just-In-Time (JIT) compiler that converts bytecode into native machine code specific to the underlying hardware. This machine code is then executed directly by the CPU. The JIT compiler optimizes the code during runtime, improving performance. JIT means the code is being compiled at the same time the program is running.

  5. Execution: The JVM executes the native machine code, running your Java program. The JVM also includes a garbage collector, which automatically manages memory by reclaiming memory used by objects that are no longer needed.

Calling Java from Kotlin

Intro

Almost all Java code can be used without any problem. In the following example, we use the ArrayList class from java.util and iterate over it.

Kotlin:

carbon (2)

Getters and Setters

Methods that follow the convention for getters and setters are represented as properties in Kotlin; these are called synthetic properties. Boolean access methods (where the getter's name starts with 'is' and the setter's name starts with 'set') are represented as properties that have the same name as the getter method.

Java:

carbon (3)

Kotlin:

carbon (4)

Methods that return "Void"

If a method in Java returns "void," once called by Kotlin, it will return "Unit." If that return value is used in Kotlin, it will be assigned the value "Unit" by default, because the compiler will know by default that the function returns "void."

Java:

carbon (6)

Kotlin:

carbon (7)

Identifiers in Java that are keywords in Kotlin

Some of Kotlin's keywords are valid identifiers in Java: in, object, is, and others. If a Java library uses a Kotlin keyword for a method, you can still call the method by escaping it with the backtick character (`). As a note, it is considered a best practice not to use any of Kotlin's strict keywords as method or field names.

Java:

carbon (8)

Kotlin:

carbon (9)

Strict Null Safety

Any reference in Java can be null, which makes Kotlin's requirement for "strict null safety" impractical for objects coming from Java.

Java declaration types are treated in Kotlin in a specific way and are called platform types.

What are "Platform Types"?

Platform types are types that the Kotlin compiler infers from Java code and may have an unknown or unspecified nullability. Essentially, platform types can be treated as nullable or non-nullable in Kotlin.

Null checks are relaxed for these types, so the safety guarantees for them are the same as in Java.

Java:

carbon (10)

Kotlin:

carbon (11)

Specifying nullability using annotations

Java types that have nullability annotations are not represented as platform types, but rather as actual Kotlin types that either accept nulls or not. The compiler supports various types of nullability annotations. Specifying nullability through annotations is indeed considered a best practice.

Java:

carbon (12)

Kotlin:

carbon (13)

Calling Kotlin from Java

Renaming Functions

When using Kotlin, you can rename the function name when consumed from Java using the @JvmName annotation. This is necessary due to the idiomatic differences between both languages.

Kotlin:

carbon (14)

Java:

carbon (15)

A good practice is to use the similar annotation @file:JvmName when having top-level functions or properties to provide a nice name. This is because having a file named "MyClass.kt" would result in a class called "MyClassKt"

Kotlin

carbon (16)

Java:

carbon (17)

Overloading Methods with Default Values

When having functions with parameters with default values, it is likely that we will need to generate method overloads to cover the different use cases from Java. For this, we can use the @JvmOverloads annotation, which will generate the overload methods.

Kotlin:

carbon (18)

Java:

carbon (19)

Exposing properties as fields of a class

To expose a property as a field and avoid the generation of "getter/setter" methods, we can implement the @JvmField annotation.

Kotlin:

carbon (20)

Java:

carbon (21)

Additionally, this annotation is used to expose public "non-constant" properties that are effectively constant in a "companion object" as static fields.

Without the annotation, these properties are only available as instance "getters" with strange names in the static companion field. On the other hand, using @JvmStatic instead of @JvmField moves the oddly named "getters" to static methods in the class, which should also be avoided.

With no annotation

Kotlin:

carbon (22)

Java:

carbon (24)

With @JvmStatic annotation

Kotlin:

carbon (23)

Java:

carbon (25)

With @JvmField annotation

Kotlin:

carbon (26)

Java:

carbon (27)

What is the @JvmStatic Annotation?

@JvmStatic is used to indicate that a method within a companion object, an object declaration, or a named object should be generated as a static method in the Java bytecode. This makes it easier to call these methods from Java, as they appear as normal static methods.

When using the @JvmStatic annotation, the Kotlin compiler generates additional static methods in the companion object or object declaration, making them accessible in a static context from Java, instead of being compiled as instance methods.

Without

Kotlin:

carbon (28)

Java:

carbon (30)

With

Kotlin:

carbon (29)

Java:

carbon (31)

About

This is a small public project containing all the examples given in the Kotlin-Java interoperability presentation.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published