KotlinコードをJavaから呼び出すとき
デフォルト引数
Kotlinのデフォルト引数付き関数をJavaから扱いたい場合、全ての引数を指定しなければなりません。
ですが、関数に@JvmOverload
アノテーションを付加すると自動的にオーバーロードメソッドが生成されます。
// Kotlin
class OverloadSample {
@JvmOverloads // アノテーションをつけると、Javaから呼び出し可能なオーバーロードメソッドが生成される
fun test(arg1: Boolean = true, arg2: Int = 1, arg3: String = "true") : Boolean {
return arg1 && arg2 == 1 && arg3 == "true"
}
}
Javaからの呼び出しコードを実装してみます。
// Java
OverloadSample os = new OverloadSample();
os.test(true, 1, "true");
os.test(true, 1);
os.test(true);
トップレベル関数、プロパティ
クラスに属さないトップレベルのKotlin関数をJavaから呼び出す方法です。
Kotlinのトップレベル関数は
ソースファイル名+Kt
という名前のクラスが生成され、
そのクラスのstatic関数へコンパイルされます。
// Utility.kt
fun doSomething() {
// Do something
}
// Java
UtilityKt.doSomething();
上記のソースファイル名+Kt
というクラス名を変更したい場合は@JvmName
アノテーションを使います。このアノテーションはパッケージに記述しまし。
// Utility.kt
@file: JvmName("Util")
package com.sample
fun doSomething() {
// Do something
}
// Java
Util.doSomething();
拡張関数
拡張関数はトップレベル関数と同じく、ソースファイル名+Kt
という名前のクラスのstatic関数としてコンパイルされます。Javaから呼び出す場合は、thisとなるオブジェクトが第一引数となります。
// StringUtility.kt
fun String.join(otherString: String) : String {
return this + otherString
}
// Java
StringUtilityKt.join("Hello, ", "World!");
objectクラス
objectクラスをJavaからみると、INSTANCE
というstaticフィールドを持ったクラスとなります。objectクラスのプロパティか関数にアクセスするには、このINSTANCE
を経由します。
// Kotlin
object LogUtil {
fun debug(log: String) {
//
}
}
// Java
LogUtil.INSTANCE.debug("completed!");
JavaコードをKotlinから呼び出すとき
プラットフォーム型
Java関数の戻り値をKotlinコードで受ける場合など、
その戻り値がnull許容型か否かは@NonNull
と@Nullable
の
アノテーションで判断されます。
// Java
public class Sample {
@NonNull
String getString1() {
return //
}
@Nullable
String getString2() {
return //
}
}
Kotlinで呼び出すと以下のようになります。
// Kotlin
val sample = Sample()
val str1 = sample.string1 // 非null許容型
val str2 = sample.string2 // null許容型
ただし、@NonNull
や@Nullable
のアノテーションは
コンパイル時に強制力を持つものではないので注意が必要です。
では、アノテーションをつけない場合は...
// Java
public class Sample {
// アノテーション無し
String getString3() {
return //
}
}
Kotlinから呼び出してみます。
// Kotlin
val sample = Sample()
val str3 = sample.string3 // String!
String!
という型になります。
この!
のついた型をプラットフォーム型といいます。
null許容型でも非null許容型でも扱える、どっちも型です。
Nullであるか否かを開発者に委ねる考え方です。
// Kotlin
val sample = Sample()
val str = sample.string3
val length = str.length // 非null許容型として扱う
val char = str?.get(0) // null許容型として扱う
static関数、staticフィールド
何らかの理由でstatic関数やフィールドが必要な状況があり得ます。
例えば...
Kotlinでstaticっぽく使えるcompanion object
。
ここでアノテーションを使うと、Javaのstaticとしてコンパイルされます。
// Kotlin
class Sample {
companion object {
@JvmField // staticフィールドへのコンパイルを指定するアノテーション
var TAG: String = "Sample"
@JvmStatic // static関数へのコンパイルを指定するアノテーション
fun tag(): String {
return "Sample"
}
}
}
// Java
String tag = Sample.TAG;
tag = Sample.tag();
SAM変換
特定の条件下において、
Javaのインターフェースを実装したクラスをラムダ式で作ることができます。
val executor: ThreadPoolExecutor
// executeメソッドの引数にはRunnableを実装したオブジェクトを渡す
executor.execute(object: Runnable{
override fun run() {
//
}
})
// SAM変換により、ラムダ式で表現可能!
executor.execute {
//
}
KotlinでSAM変換が有効となる条件は以下です。
- Javaで宣言されたインターフェースであること
- 抽象メソッドが1つだけのインターフェースであること
Kotlinには適切な関数型が存在するのでKotlinで宣言したインターフェースではSAM変換は有効になりません