Skip to content

KotlinからのJavaの呼び出し

KotlinはJavaとの相互運用性を考慮して設計されています。既存のJavaコードはKotlinから自然な形で呼び出すことができ、KotlinコードもJavaからスムーズに使用できます。このセクションでは、KotlinからJavaコードを呼び出す際の詳細について説明します。

ほぼすべてのJavaコードは問題なく使用できます。

kotlin
import java.util.*

fun demo(source: List<Int>) {
    val list = ArrayList<Int>()
    // 'for'-loops work for Java collections:
    for (item in source) {
        list.add(item)
    }
    // Operator conventions work as well:
    for (i in 0..source.size - 1) {
        list[i] = source[i] // get and set are called
    }
}

ゲッターとセッター

Javaのゲッターとセッターの規約(getで始まる引数なしのメソッド、setで始まる単一引数のメソッド)に従うメソッドは、Kotlinではプロパティとして表現されます。このようなプロパティは合成プロパティsynthetic properties)とも呼ばれます。Booleanアクセサメソッド(ゲッターの名前がisで始まり、セッターの名前がsetで始まるもの)は、ゲッターメソッドと同じ名前を持つプロパティとして表現されます。

kotlin
import java.util.Calendar

fun calendarDemo() {
    val calendar = Calendar.getInstance()
    if (calendar.firstDayOfWeek == Calendar.SUNDAY) { // call getFirstDayOfWeek()
        calendar.firstDayOfWeek = Calendar.MONDAY // call setFirstDayOfWeek()
    }
    if (!calendar.isLenient) { // call isLenient()
        calendar.isLenient = true // call setLenient()
    }
}

上記のcalendar.firstDayOfWeekは、合成プロパティの一例です。

なお、Javaクラスがセッターしか持たない場合、Kotlinはセット専用プロパティをサポートしないため、Kotlinではプロパティとして表示されません。

Java合成プロパティ参照

この機能は実験的(Experimental)です。いつでも廃止または変更される可能性があります。 評価目的でのみ使用することをお勧めします。

Kotlin 1.8.20以降、Java合成プロパティへの参照を作成できるようになりました。以下のJavaコードを考えてみましょう。

java
public class Person {
    private String name;
    private int age;

    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public int getAge() {
        return age;
    }
}

Kotlinでは常にperson.ageと書くことができ、ageは合成プロパティです。これに加えて、Person::ageperson::ageへの参照も作成できるようになりました。nameについても同様です。

kotlin
val persons = listOf(Person("Jack", 11), Person("Sofie", 12), Person("Peter", 11))
    persons
         // Call a reference to Java synthetic property:
        .sortedBy(Person::age)
         // Call Java getter via the Kotlin property syntax:
        .forEach { person -> println(person.name) }

Java合成プロパティ参照を有効にする方法

この機能を有効にするには、-language-version 2.1コンパイラオプションを設定します。Gradleプロジェクトでは、build.gradle(.kts)に以下を追加することで設定できます。

kotlin
tasks
    .withType<org.jetbrains.kotlin.gradle.tasks.KotlinCompilationTask<*>>()
    .configureEach {
        compilerOptions
            .languageVersion
            .set(
                org.jetbrains.kotlin.gradle.dsl.KotlinVersion.KOTLIN_2_1
            )
    }
groovy
tasks
    .withType(org.jetbrains.kotlin.gradle.tasks.KotlinCompilationTask.class)
    .configureEach {
        compilerOptions.languageVersion
            = org.jetbrains.kotlin.gradle.dsl.KotlinVersion.KOTLIN_2_1
}

Kotlin 1.9.0より前では、この機能を有効にするには-language-version 1.9コンパイラオプションを設定する必要がありました。

voidを返すメソッド

Javaメソッドがvoidを返す場合、Kotlinから呼び出すとUnitを返します。 もしその戻り値が何らかの形で使用されたとしても、値自体は事前にわかっているため(Unitであるため)、Kotlinコンパイラによって呼び出し元で割り当てられます。

KotlinのキーワードであるJava識別子のエスケープ

Kotlinの一部のキーワードは、Javaでは有効な識別子です。例えば、inobjectisなどです。 JavaライブラリがKotlinのキーワードをメソッド名に使用している場合でも、バッククォート(`)文字でエスケープすることでメソッドを呼び出すことができます。

kotlin
foo.`is`(bar)

Null安全性とプラットフォーム型

Javaのすべての参照はnullになる可能性があるため、Javaから来るオブジェクトに対してKotlinの厳格なNull安全性の要件を適用するのは現実的ではありません。 Javaの宣言の型はKotlinでは特定の方法で扱われ、プラットフォーム型と呼ばれます。これらの型に対してはNullチェックが緩和され、安全性保証はJavaと同じになります(詳細は以下を参照)。

以下の例を考えてみましょう。

kotlin
val list = ArrayList<String>() // non-null (constructor result)
list.add("Item")
val size = list.size // non-null (primitive int)
val item = list[0] // platform type inferred (ordinary Java object)

プラットフォーム型の変数に対してメソッドを呼び出す場合、Kotlinはコンパイル時にNull許容性エラーを発行しませんが、Nullポインター例外またはKotlinがNullの伝播を防ぐために生成するアサーションによって、実行時に呼び出しが失敗する可能性があります。

kotlin
item.substring(1) // allowed, throws an exception if item == null

プラットフォーム型は表記不可能(non-denotable)であり、言語で明示的に記述することはできません。 プラットフォーム値がKotlin変数に割り当てられる場合、型推論に頼るか(上記の例のitemのように、変数は推論されたプラットフォーム型になります)、または期待する型を選択できます(Null許容型と非Null許容型の両方が許可されます)。

kotlin
val nullable: String? = item // allowed, always works
val notNull: String = item // allowed, may fail at runtime

非Null許容型を選択した場合、コンパイラは代入時にアサーションを出力します。これにより、Kotlinの非Null許容変数がNullを保持することを防ぎます。アサーションは、プラットフォーム値を非Null値を期待するKotlin関数に渡す場合や、その他の場合にも出力されます。 全体として、ジェネリクスによっては完全に排除できない場合もありますが、コンパイラはプログラム全体にNullが伝播しないように最善を尽くします。

プラットフォーム型の表記法

前述のとおり、プラットフォーム型はプログラム中で明示的に言及できないため、言語にはそれらを記述するための構文がありません。 しかし、コンパイラやIDEは(エラーメッセージやパラメータ情報などで)それらを表示する必要がある場合があるため、ニーモニック表記が存在します。

  • T! は「TまたはT?」を意味します。
  • (Mutable)Collection<T>! は「TのJavaコレクション。可変または不変、Null許容または非Null許容」を意味します。
  • Array<(out) T>! は「T(またはTのサブタイプ)のJava配列。Null許容または非Null許容」を意味します。

Null許容性アノテーション

Null許容性アノテーションを持つJava型は、プラットフォーム型としてではなく、実際のNull許容または非Null許容Kotlin型として表現されます。コンパイラは、いくつかの種類のNull許容性アノテーションをサポートしています。

  • JetBrains (org.jetbrains.annotationsパッケージの@Nullableおよび@NotNull)
  • JSpecify (org.jspecify.annotations)
  • Android (com.android.annotationsおよびandroid.support.annotations)
  • JSR-305 (javax.annotation、詳細は以下を参照)
  • FindBugs (edu.umd.cs.findbugs.annotations)
  • Eclipse (org.eclipse.jdt.annotation)
  • Lombok (lombok.NonNull)
  • RxJava 3 (io.reactivex.rxjava3.annotations)

特定の種類のNull許容性アノテーションからの情報に基づいて、コンパイラがNull許容性の不一致を報告するかどうかを指定できます。コンパイラオプション-Xnullability-annotations=@<package-name>:<report-level>を使用します。引数には、完全修飾されたNull許容性アノテーションパッケージと、以下のいずれかのレポートレベルを指定します。

  • ignore: Null許容性の不一致を無視します。
  • warn: 警告を報告します。
  • strict: エラーを報告します。

サポートされているNull許容性アノテーションの完全なリストは、Kotlinコンパイラのソースコードで確認できます。

型引数と型パラメータのアノテーション

総称型(generic types)の型引数と型パラメータにもNull許容性情報を指定するアノテーションを付けることができます。

このセクションのすべての例では、org.jetbrains.annotationsパッケージのJetBrains Null許容性アノテーションを使用しています。

型引数

Javaの宣言に付けられたこれらのアノテーションを考えてみましょう。

java
@NotNull
Set<@NotNull String> toSet(@NotNull Collection<@NotNull String> elements) { ... }

これらはKotlinで以下のシグネチャになります。

kotlin
fun toSet(elements: (Mutable)Collection<String>) : (Mutable)Set<String> { ... }

型引数から@NotNullアノテーションが欠落している場合、代わりにプラットフォーム型が得られます。

kotlin
fun toSet(elements: (Mutable)Collection<String!>) : (Mutable)Set<String!> { ... }

Kotlinは、基底クラスやインターフェースの型引数に関するNull許容性アノテーションも考慮します。例えば、以下に示すシグネチャを持つ2つのJavaクラスがあるとします。

java
public class Base<T> {}
java
public class Derived extends Base<@Nullable String> {}

Kotlinコードでは、Base<String>が想定される場所でDerivedのインスタンスを渡すと、警告が生成されます。

kotlin
fun takeBaseOfNotNullStrings(x: Base<String>) {}

fun main() {
    takeBaseOfNotNullStrings(Derived()) // warning: nullability mismatch
}

Derivedの上限はBase<String?>に設定されており、これはBase<String>とは異なります。

KotlinにおけるJavaジェネリクスの詳細をご覧ください。

型パラメータ

デフォルトでは、KotlinとJavaの両方におけるプレーンな型パラメータのNull許容性は未定義です。Javaでは、Null許容性アノテーションを使用してそれを指定できます。Baseクラスの型パラメータにアノテーションを付けてみましょう。

java
public class Base<@NotNull T> {}

Baseから継承する場合、Kotlinは非Null許容の型引数または型パラメータを期待します。 したがって、以下のKotlinコードは警告を生成します。

kotlin
class Derived<K> : Base<K> {} // warning: K has undefined nullability

K : Anyという上限を指定することで、これを修正できます。

Kotlinは、Javaの型パラメータの上限に対するNull許容性アノテーションもサポートしています。Baseに上限を追加してみましょう。

java
public class BaseWithBound<T extends @NotNull Number> {}

Kotlinはこれを以下のように変換します。

kotlin
class BaseWithBound<T : Number> {}

そのため、Null許容型を型引数または型パラメータとして渡すと警告が生成されます。

型引数と型パラメータのアノテーションは、Java 8以降のターゲットで動作します。この機能は、Null許容性アノテーションがTYPE_USEターゲットをサポートしている必要があります(org.jetbrains.annotationsはバージョン15以降でこれをサポートしています)。

Null許容性アノテーションがTYPE_USEターゲットに加えて型に適用可能な他のターゲットをサポートしている場合、TYPE_USEが優先されます。例えば、@NullableTYPE_USEMETHODの両方のターゲットを持つ場合、Javaのメソッドシグネチャ@Nullable String[] f()はKotlinでfun f(): Array<String?>!になります。

JSR-305サポート

JSR-305で定義されている@Nonnullアノテーションは、Java型のNull許容性を示すためにサポートされています。

@Nonnull(when = ...)の値がWhen.ALWAYSの場合、アノテーションが付けられた型は非Null許容として扱われます。When.MAYBEWhen.NEVERはNull許容型を示し、When.UNKNOWNは型をプラットフォーム型に強制します。

ライブラリはJSR-305アノテーションに対してコンパイルできますが、アノテーションアーティファクト(例:jsr305.jar)をライブラリ利用者のコンパイル依存関係にする必要はありません。Kotlinコンパイラは、クラスパスにアノテーションが存在しなくても、ライブラリからJSR-305アノテーションを読み取ることができます。

カスタムNull許容性修飾子 (KEEP-79)もサポートされています(以下参照)。

型修飾子ニックネーム

アノテーション型が@TypeQualifierNicknameとJSR-305の@Nonnull(または@CheckForNullなどの別のニックネーム)の両方でアノテーションされている場合、そのアノテーション型自体が正確なNull許容性を取得するために使用され、そのNull許容性アノテーションと同じ意味を持ちます。

java
@TypeQualifierNickname
@Nonnull(when = When.ALWAYS)
@Retention(RetentionPolicy.RUNTIME)
public @interface MyNonnull {
}

@TypeQualifierNickname
@CheckForNull // a nickname to another type qualifier nickname
@Retention(RetentionPolicy.RUNTIME)
public @interface MyNullable {
}

interface A {
    @MyNullable String foo(@MyNonnull String x);
    // in Kotlin (strict mode): `fun foo(x: String): String?`

    String bar(List<@MyNonnull String> x);
    // in Kotlin (strict mode): `fun bar(x: List<String>!): String!`
}

型修飾子デフォルト

@TypeQualifierDefaultは、適用されると、アノテーションされた要素のスコープ内でデフォルトのNull許容性を定義するアノテーションを導入することができます。

このようなアノテーション型は、それ自体が@Nonnull(またはそのニックネーム)と@TypeQualifierDefault(...)の両方で、1つ以上のElementType値と共にアノテーションされている必要があります。

  • ElementType.METHOD: メソッドの戻り値の型
  • ElementType.PARAMETER: 値パラメータ
  • ElementType.FIELD: フィールド
  • ElementType.TYPE_USE: 型引数、型パラメータの上限、ワイルドカード型を含む任意の型

デフォルトのNull許容性は、型自体にNull許容性アノテーションが付けられていない場合に使用され、デフォルトは、型使用法に一致するElementTypeを持つ型修飾子デフォルトアノテーションでアノテーションされた最も内側の囲む要素によって決定されます。

java
@Nonnull
@TypeQualifierDefault({ElementType.METHOD, ElementType.PARAMETER})
public @interface NonNullApi {
}

@Nonnull(when = When.MAYBE)
@TypeQualifierDefault({ElementType.METHOD, ElementType.PARAMETER, ElementType.TYPE_USE})
public @interface NullableApi {
}

@NullableApi
interface A {
    String foo(String x); // fun foo(x: String?): String?

    @NotNullApi // overriding default from the interface
    String bar(String x, @Nullable String y); // fun bar(x: String, y: String?): String

    // The List<String> type argument is seen as nullable because of `@NullableApi`
    // having the `TYPE_USE` element type:
    String baz(List<String> x); // fun baz(List<String?>?): String?

    // The type of `x` parameter remains platform because there's an explicit
    // UNKNOWN-marked nullability annotation:
    String qux(@Nonnull(when = When.UNKNOWN) String x); // fun baz(x: String!): String?
}

この例の型は、strictモードが有効な場合にのみ適用されます。それ以外の場合、プラットフォーム型はそのまま残ります。 @UnderMigrationアノテーションコンパイラ設定のセクションを参照してください。

パッケージレベルのデフォルトNull許容性もサポートされています。

java
// FILE: test/package-info.java
@NonNullApi // declaring all types in package 'test' as non-nullable by default
package test;

@UnderMigrationアノテーション

@UnderMigrationアノテーション(kotlin-annotations-jvmという別個のアーティファクトで提供)は、ライブラリのメンテナーがNull許容性型修飾子の移行ステータスを定義するために使用できます。

@UnderMigration(status = ...)のステータス値は、アノテーション付き型のKotlinでの不適切な使用(例:@MyNullableアノテーション付き型値を非Nullとして使用する)をコンパイラがどのように扱うかを指定します。

  • MigrationStatus.STRICT: アノテーションを通常のNull許容性アノテーションとして機能させ、不適切な使用に対してエラーを報告し、アノテーション付き宣言内の型にKotlinで認識されるように影響を与えます。
  • MigrationStatus.WARN: 不適切な使用はエラーではなくコンパイル警告として報告されますが、アノテーション付き宣言内の型はプラットフォーム型として残ります。
  • MigrationStatus.IGNORE: コンパイラがNull許容性アノテーションを完全に無視します。

ライブラリのメンテナーは、型修飾子のニックネームと型修飾子のデフォルトの両方に@UnderMigrationステータスを追加できます。

java
@Nonnull(when = When.ALWAYS)
@TypeQualifierDefault({ElementType.METHOD, ElementType.PARAMETER})
@UnderMigration(status = MigrationStatus.WARN)
public @interface NonNullApi {
}

// The types in the class are non-nullable, but only warnings are reported
// because `@NonNullApi` is annotated `@UnderMigration(status = MigrationStatus.WARN)`
@NonNullApi
public class Test {}

Null許容性アノテーションの移行ステータスは、その型修飾子ニックネームには継承されませんが、デフォルトの型修飾子での使用には適用されます。

デフォルトの型修飾子が型修飾子のニックネームを使用し、それらが両方とも@UnderMigrationである場合、デフォルトの型修飾子からのステータスが使用されます。

コンパイラ設定

JSR-305のチェックは、以下のオプション(およびその組み合わせ)とともに-Xjsr305コンパイラフラグを追加することで設定できます。

  • -Xjsr305={strict|warn|ignore}: @UnderMigrationアノテーションではないアノテーションの動作を設定します。 カスタムNull許容性修飾子、特に@TypeQualifierDefaultは、すでに多くの著名なライブラリに普及しており、ユーザーはJSR-305サポートを含むKotlinバージョンに更新する際にスムーズに移行する必要があるかもしれません。Kotlin 1.1.60以降、このフラグは@UnderMigrationアノテーションではないものにのみ影響します。

  • -Xjsr305=under-migration:{strict|warn|ignore}: @UnderMigrationアノテーションの動作を上書きします。 ユーザーはライブラリの移行ステータスについて異なる見解を持つかもしれません。公式の移行ステータスがWARNであるにもかかわらずエラーを発生させたい場合や、その逆の場合、または一部のエラー報告を移行が完了するまで延期したい場合があります。

  • -Xjsr305=@<fq.name>:{strict|warn|ignore}: 単一のアノテーションの動作を上書きします。<fq.name>はアノテーションの完全修飾クラス名です。異なるアノテーションに対して複数回出現する場合があります。これは特定のライブラリの移行状態を管理するのに役立ちます。

strictwarnignoreの値はMigrationStatusと同じ意味を持ち、strictモードのみがアノテーション付き宣言内の型にKotlinで認識されるように影響します。

注:組み込みのJSR-305アノテーション@Nonnull@Nullable@CheckForNullは常に有効であり、 -Xjsr305フラグによるコンパイラ設定に関わらず、Kotlinにおけるアノテーション付き宣言の型に影響を与えます。

例えば、コンパイラ引数に-Xjsr305=ignore -Xjsr305=under-migration:ignore [email protected]:warnを追加すると、コンパイラは@org.library.MyNullableでアノテーションされた型の不適切な使用に対して警告を生成し、他のすべてのJSR-305アノテーションを無視します。

デフォルトの動作は-Xjsr305=warnと同じです。strictの値は実験的と見なすべきです(将来的により多くのチェックが追加される可能性があります)。

マップされる型

Kotlinは、特定のJava型を特別に扱います。これらの型はJavaから「そのまま」ロードされるのではなく、対応するKotlin型にマップされます。マッピングはコンパイル時にのみ重要であり、実行時の表現は変更されません。 Javaのプリミティブ型は、対応するKotlin型にマップされます(プラットフォーム型を考慮して)。

Java型Kotlin型
bytekotlin.Byte
shortkotlin.Short
intkotlin.Int
longkotlin.Long
charkotlin.Char
floatkotlin.Float
doublekotlin.Double
booleankotlin.Boolean

一部の非プリミティブな組み込みクラスもマップされます。

Java型Kotlin型
java.lang.Objectkotlin.Any!
java.lang.Cloneablekotlin.Cloneable!
java.lang.Comparablekotlin.Comparable!
java.lang.Enumkotlin.Enum!
java.lang.annotation.Annotationkotlin.Annotation!
java.lang.CharSequencekotlin.CharSequence!
java.lang.Stringkotlin.String!
java.lang.Numberkotlin.Number!
java.lang.Throwablekotlin.Throwable!

Javaのボックス化されたプリミティブ型は、Null許容Kotlin型にマップされます。

Java型Kotlin型
java.lang.Bytekotlin.Byte?
java.lang.Shortkotlin.Short?
java.lang.Integerkotlin.Int?
java.lang.Longkotlin.Long?
java.lang.Characterkotlin.Char?
java.lang.Floatkotlin.Float?
java.lang.Doublekotlin.Double?
java.lang.Booleankotlin.Boolean?

型パラメータとして使用されるボックス化されたプリミティブ型は、プラットフォーム型にマップされることに注意してください。 例えば、List<java.lang.Integer>はKotlinではList<Int!>になります。

コレクション型はKotlinでは読み取り専用または可変になる場合があるため、Javaのコレクションは次のようにマップされます(この表のすべてのKotlin型はkotlin.collectionsパッケージにあります)。

Java型Kotlin読み取り専用型Kotlin可変型ロードされるプラットフォーム型
Iterator<T>Iterator<T>MutableIterator<T>(Mutable)Iterator<T>!
Iterable<T>Iterable<T>MutableIterable<T>(Mutable)Iterable<T>!
Collection<T>Collection<T>MutableCollection<T>(Mutable)Collection<T>!
Set<T>Set<T>MutableSet<T>(Mutable)Set<T>!
List<T>List<T>MutableList<T>(Mutable)List<T>!
ListIterator<T>ListIterator<T>MutableListIterator<T>(Mutable)ListIterator<T>!
Map<K, V>Map<K, V>MutableMap<K, V>(Mutable)Map<K, V>!
Map.Entry<K, V>Map.Entry<K, V>MutableMap.MutableEntry<K,V>(Mutable)Map.(Mutable)Entry<K, V>!

Javaの配列は、以下で述べられているようにマップされます。

Java型Kotlin型
int[]kotlin.IntArray!
String[]kotlin.Array<(out) String!>!

これらのJava型の静的メンバーは、Kotlin型のコンパニオンオブジェクトでは直接アクセスできません。それらを呼び出すには、java.lang.Integer.toHexString(foo)のように、Java型の完全修飾名を使用します。

KotlinにおけるJavaジェネリクス

KotlinのジェネリクスはJavaのジェネリクスとは少し異なります(ジェネリクスを参照)。 Java型をKotlinにインポートする際、以下の変換が行われます。

  • Javaのワイルドカードは型プロジェクションに変換されます。

    • Foo<? extends Bar>Foo<out Bar!>! になります。
    • Foo<? super Bar>Foo<in Bar!>! になります。
  • Javaの生の型(raw types)はスタープロジェクションに変換されます。

    • ListList<*>!、つまり List<out Any?>! になります。

Javaと同様に、Kotlinのジェネリクスは実行時には保持されません。オブジェクトはコンストラクタに渡された実際の型引数に関する情報を持ちません。例えば、ArrayList<Integer>()ArrayList<Character>()は区別できません。 このため、ジェネリクスを考慮したisチェックを実行することは不可能です。 Kotlinでは、スタープロジェクションされた総称型に対してのみisチェックが可能です。

kotlin
if (a is List<Int>) // Error: cannot check if it is really a List of Ints
// but
if (a is List<*>) // OK: no guarantees about the contents of the list

Java配列

Kotlinの配列は不変であり、Javaとは異なります。これは、KotlinがArray<String>Array<Any>に割り当てることを許可しないことを意味し、これにより起こりうる実行時エラーを防ぎます。サブクラスの配列をスーパークラスの配列としてKotlinメソッドに渡すことも禁止されていますが、Javaメソッドの場合はArray<(out) String>!のようなプラットフォーム型を介して許可されます。

配列は、ボクシング/アンボクシング操作のコストを避けるために、Javaプラットフォームでプリミティブデータ型と共に使用されます。 Kotlinはこれらの実装の詳細を隠蔽するため、Javaコードとインターフェースするには回避策が必要です。 このケースを処理するために、すべてのプリミティブ配列型(IntArrayDoubleArrayCharArrayなど)に特化したクラスがあります。 これらはArrayクラスとは関連しておらず、最高のパフォーマンスのためにJavaのプリミティブ配列にコンパイルされます。

インデックスのint配列を受け入れるJavaメソッドがあるとします。

java
public class JavaArrayExample {
    public void removeIndices(int[] indices) {
        // code here...
    }
}

プリミティブ値の配列を渡すには、Kotlinで次のようにします。

kotlin
val javaObj = JavaArrayExample()
val array = intArrayOf(0, 1, 2, 3)
javaObj.removeIndices(array)  // passes int[] to method

JVMバイトコードにコンパイルされる際、コンパイラは配列へのアクセスを最適化し、オーバーヘッドが発生しないようにします。

kotlin
val array = arrayOf(1, 2, 3, 4)
array[1] = array[1] * 2 // no actual calls to get() and set() generated
for (x in array) { // no iterator created
    print(x)
}

インデックスでナビゲートする場合でも、オーバーヘッドは発生しません。

kotlin
for (i in array.indices) { // no iterator created
    array[i] += 2
}

最後に、inチェックにもオーバーヘッドはありません。

kotlin
if (i in array.indices) { // same as (i >= 0 && i < array.size)
    print(array[i])
}

Javaの可変長引数(varargs)

Javaクラスでは、インデックスに対して可変数の引数(varargs)を持つメソッド宣言が使用されることがあります。

java
public class JavaArrayExample {

    public void removeIndicesVarArg(int... indices) {
        // code here...
    }
}

この場合、IntArrayを渡すにはスプレッド演算子*を使用する必要があります。

kotlin
val javaObj = JavaArrayExample()
val array = intArrayOf(0, 1, 2, 3)
javaObj.removeIndicesVarArg(*array)

演算子

Javaには演算子構文を使用することが理にかなっているメソッドをマークする方法がないため、Kotlinでは適切な名前とシグネチャを持つ任意のJavaメソッドを演算子オーバーロードやその他の規約(invoke()など)として使用できます。中置呼び出し構文を使用してJavaメソッドを呼び出すことは許可されていません。

チェック例外

Kotlinでは、すべての例外はアンチェックです。つまり、コンパイラはそれらをキャッチすることを強制しません。 そのため、チェック例外を宣言するJavaメソッドを呼び出す場合でも、Kotlinは何も強制しません。

kotlin
fun render(list: List<*>, to: Appendable) {
    for (item in list) {
        to.append(item.toString()) // Java would require us to catch IOException here
    }
}

Objectクラスのメソッド

Java型がKotlinにインポートされると、java.lang.Object型のすべての参照はAnyに変換されます。 Anyはプラットフォーム固有ではないため、メンバーとしてtoString()hashCode()equals()のみを宣言します。 したがって、java.lang.Objectの他のメンバーを利用可能にするために、Kotlinは拡張関数を使用します。

wait()/notify()

wait()およびnotify()メソッドはAny型の参照では利用できません。これらの使用は一般的にjava.util.concurrentを優先して推奨されていません。どうしてもこれらのメソッドを呼び出す必要がある場合は、java.lang.Objectにキャストできます。

kotlin
(foo as java.lang.Object).wait()

getClass()

オブジェクトのJavaクラスを取得するには、クラス参照java拡張プロパティを使用します。

kotlin
val fooClass = foo::class.java

上記のコードはバウンドクラスリファレンスを使用しています。javaClass拡張プロパティを使用することもできます。

kotlin
val fooClass = foo.javaClass

clone()

clone()をオーバーライドするには、クラスがkotlin.Cloneableを継承する必要があります。

kotlin
class Example : Cloneable {
    override fun clone(): Any { ... }
}

『Effective Java 第3版』の項目13「cloneを慎重にオーバーライドする」も忘れないでください。

finalize()

finalize()をオーバーライドするには、overrideキーワードを使用せずに単純に宣言するだけです。

kotlin
class C {
    protected fun finalize() {
        // finalization logic
    }
}

Javaのルールによると、finalize()privateであってはなりません。

Javaクラスからの継承

Kotlinのクラスは、最大1つのJavaクラス(および任意の数のJavaインターフェース)をスーパークラスとすることができます。

静的メンバーへのアクセス

Javaクラスの静的メンバーは、これらのクラスの「コンパニオンオブジェクト」を形成します。このような「コンパニオンオブジェクト」を値として渡すことはできませんが、メンバーには明示的にアクセスできます。例えば、次のようになります。

kotlin
if (Character.isLetter(a)) { ... }

マップされる型であるJava型の静的メンバーにアクセスするには、java.lang.Integer.bitCount(foo)のように、Java型の完全修飾名を使用します。

Javaリフレクション

JavaリフレクションはKotlinクラスで動作し、その逆も同様です。前述のとおり、instance::class.javaClassName::class.java、またはinstance.javaClassを使用してjava.lang.Classを介してJavaリフレクションに入ることができます。 ClassName.javaClassをこの目的で使用しないでください。これはClassNameのコンパニオンオブジェクトクラスを参照し、ClassName.Companion::class.javaと同じであり、ClassName::class.javaとは異なります。

各プリミティブ型には2つの異なるJavaクラスがあり、Kotlinは両方を取得する方法を提供します。例えば、Int::class.javaはプリミティブ型自体を表すクラスインスタンスを返します。これはJavaのInteger.TYPEに相当します。対応するラッパー型のクラスを取得するには、JavaのInteger.classと同等のInt::class.javaObjectTypeを使用します。

その他のサポートされるケースには、KotlinプロパティのJavaゲッター/セッターメソッドまたはバッキングフィールドの取得、JavaフィールドのKPropertyの取得、KFunctionのJavaメソッドまたはコンストラクタの取得、およびその逆が含まれます。

SAM変換

KotlinはJavaとKotlinインターフェースの両方でSAM変換をサポートしています。 Javaに対するこのサポートは、Kotlinの関数リテラルが、単一の非デフォルトメソッドを持つJavaインターフェースの実装に自動的に変換できることを意味します。ただし、インターフェースメソッドのパラメータ型がKotlin関数のパラメータ型と一致する必要があります。

これを使用してSAMインターフェースのインスタンスを作成できます。

kotlin
val runnable = Runnable { println("This runs in a runnable") }

…そしてメソッド呼び出しで。

kotlin
val executor = ThreadPoolExecutor()
// Java signature: void execute(Runnable command)
executor.execute { println("This runs in a thread pool") }

Javaクラスが複数の関数インターフェースを取るメソッドを持っている場合、ラムダを特定のSAM型に変換するアダプター関数を使用することで、呼び出す必要があるメソッドを選択できます。これらのアダプター関数も必要に応じてコンパイラによって生成されます。

kotlin
executor.execute(Runnable { println("This runs in a thread pool") })

SAM変換はインターフェースにのみ機能し、抽象クラスには機能しません。抽象クラスが単一の抽象メソッドしか持たない場合でも同様です。

KotlinでのJNIの使用

ネイティブ(CまたはC++)コードで実装された関数を宣言するには、external修飾子でマークする必要があります。

kotlin
external fun foo(x: Int): Double

残りの手順はJavaとまったく同じです。

プロパティのゲッターとセッターもexternalとしてマークできます。

kotlin
var myProperty: String
    external get
    external set

内部的には、これによりgetMyPropertysetMyPropertyという2つの関数が作成され、どちらもexternalとしてマークされます。

KotlinでLombokによって生成された宣言を使用する

JavaのLombokによって生成された宣言をKotlinコードで使用できます。 同じJava/Kotlin混在モジュールでこれらの宣言を生成して使用する必要がある場合は、Lombokコンパイラプラグインのページでその方法を学ぶことができます。 別のモジュールからそのような宣言を呼び出す場合、そのモジュールをコンパイルするためにこのプラグインを使用する必要はありません。