kotlinはJavaからどう見えるか?



[kotlinはjavaとの互換性を念頭において設計されています](https://kotlinlang.org/docs/reference/java-interop.html)。では、kotlinとJavaが共存している時にkotlin特有の実装と思われる機能は実際にJavaからどのように見えるのでしょうか？

# プロパティ

kotlinで`val`や`var`でプロパティの宣言をしてみます。

```kotlin:KotlinSample.kt
class KotlinClassA{
    val a:Int = 1
    var b:Int = 2
}

```

これがJavaでは

![MainActivity_java_-_kotlin-java-sample_-____Documents_github_kotlin-java-sample_.png](https://qiita-image-store.s3.amazonaws.com/0/8308/2646bbe0-eaac-1a54-3afe-8d737375c53b.png "MainActivity_java_-_kotlin-java-sample_-____Documents_github_kotlin-java-sample_.png")


`val a:Int`で宣言したものは`getA()`のgetterのみ
`var b:Int`で宣言したもの`getB()`と`setB(int i)`とgetterとsetterの両方が生成されているようです。

## get/setを使わずにプロパティアクセスしたい

kotlinのプロパティに`@JvmField`アノテーションを指定することでJavaからはget/setメソッドではなく直接プロパティとしてアクセスすることができます。

```kotlin:kotlin
class KotlinClassA{
    @JvmField val a:Int = 1
    @JvmField var b:Int = 2
}

```

これでJavaからはプロパティとしてアクセスすることができます。

```java:Java
        KotlinClassA classA = new KotlinClassA();
        int x = classA.a;
        int y = classA.b;
        classA.b = 4;

```

`val`で宣言されたプロパティはjavaとしてはfinal指定であると解釈されているため以下の記述はビルドエラーになります。

```java:Java
        classA.a = 5; // エラー: final変数aに値を代入することはできません
```


# トップレベルの関数

kotlinではソースファイル上に直接関数を宣言することができます。一方Javaではclass内のstaticあるいはinstanceメソッドとしてしか手続きを実装することができません。

こんな感じに`KotlinSample.kt`というファイルに関数の実装をしてみると

```kotlin:KotlinSample.kt

fun func():Int = 3

```

これがJavaでは

```java:MainActivity.java

	KotlinSampleKt.func();

```

ファイル名の`KotlinSample.kt`に対応するクラス`KotlinSampleKt`クラスが生成され、そのstaticメソッドとして実行することができます。

## ファイルに対応するクラス名を変えたい

このKotlinSample.ktから由来するクラス名を変更したいときは、以下のようにファイルの先頭に記述することによって任意のクラス名に変更することができます。

※ ドキュメントには記載箇所の指定はありませんが、現状package指定よりも前の行に記述する必要があるようです。
※ また、以下の実装はビルドが通りますが、何故かAndroidStudio上ではエラーとして表示されます。

```kotlin:KotlinSample.kt

@file:JvmName("KotlinSampleB")
package com.github.yamamotoj.kotlin_java_sample

fun func():Int = 3

```
Javaでは

```java:MainActivity.java

	KotlinSampleB.func();

```
のように指定したクラス名で実行することができます。



# kotlinで宣言したinterface

上記のようにkotlinのプロパティはget/setメソッドとしてJavaからアクセスできます。これはinterfaceの実装でも同様です。

```kotlin:KotlinSample.kt
interface KotlinInterface{
    val a:Int
    var b:Int
}
```

このinterfaceをJavaで実装すると？

```java:Java
    class KotlinInterfaceImpl implements KotlinInterface{

        @Override
        public int getA() {
            return 0;
        }

        @Override
        public int getB() {
            return 0;
        }

        @Override
        public void setB(int i) {

        }
    }
```

## interfaceにデフォルト実装がある場合は？

kotlinではinterfaceにデフォルトの実装を持たせることができます。

```kotlin:kotlin
interface KotlinInterface2{
    val a:Int get() = 1
    fun getValue():Int {
        return a
    }
}
```

このinterfaceをJavaで実装すると？

```java:Java
    class KotlinInterface2Impl implements KotlinInterface2{

        @Override
        public int getA() {
            return 0;
        }

        @Override
        public int getValue() {
            return 0;
        }
    }

```

普通にデフォルト実装は無視されるようですね ^^;



# Companionオブジェクト

kotlinでクラスのstaticメソッドを実装するには以下のように`companion object`を介して実装します。

```kotlin:Kotlin
class KotlinClassB {
    companion object{
        fun funcB():Int{
            return 2
        }
    }
}
```

これをJavaからアクセスすると

```java:Java
        KotlinClassB.Companion.funcB();
```

のように`Companion`オブジェクトを介してstaticにアクセスが可能です。

## `Companion`オブジェクトを介さずにstaticメソッドにアクセスする

Javaからstaticにアクセスしたいメソッドに対しては`@JmvStatic`アノテーションを付けることで

```kotlin:Kotlin
class KotlinClassB {
    companion object{
        @JvmStatic fun funcB():Int{
            return 2
        }
    }
}

```

Javaからは`Companion`オブジェクトを介さず直接メソッドにアクセスできます。

```java:Java
        KotlinClassB.funcB();
```

# シングルトンオブジェクト

kotlinでは`class`指定の代わりに`object`指定をすることによりシングルトンオブジェクトの宣言をすることができます。

```kotlin:Kotlin
object KotlinObject{
    val a:Int = 1
}
```

このオブジェクトはkotlinのソースからは

```kotlin:Kotlin
    KotlinObject.a
```

とアクセスできますがJavaからは

```java:Java
        KotlinObject.INSTANCE.getA();
```

のように`INSTANCE`というオブジェクトを介してアクセスができます。


また、`companion object`の場合と同様に直接アクセスしたいメソッドに`@JvmStatic`アノテーションを付けることで

```kotlin:Kotlin
object KotlinObject {
    @JvmStatic val a: Int = 1
}
```

Javaからは

```java:Java
	KotlinObject.getA();
```

と直接アクセスすることができます。

# Sealed class

`sealed class`は

```kotlin:Kotlin
sealed class SealedClass {
    class A : SealedClass()
    class B : SealedClass()
}
```

Javaでは普通のインナークラスとして解釈されるようです。

```java:Java
	SealedClass sealed = new SealedClass.A();
```




# Extensions

kotlinではクラスのメソッド拡張の機能があり、継承を行わずとも既存のクラスに新たにメソッドを追加することができます。

```kotlin:Kotlin

class KotlinClassA {
}

class KotlinClassB {
    fun KotlinClassA.extendClassA(): Int = 3
}

```

このように`KotlinClassB`から`KotlinClassA`のメソッドを拡張した場合、Javaでは`KotlinClassA`を引数に持つ`KotlinClassB`のメソッドとしてアクセスできます。

```java:Java
        KotlinClassA classA = new KotlinClassA();
        KotlinClassB classB = new KotlinClassB();
        classB.extendClassA(classA);
```

トップレベルの関数としてメソッドを拡張した場合は、

```kotlin:KotlinSample.kt
class KotlinClassA {
}

fun KotlinClassA.extend(): Int = 3

```

前出のようにファイル名に由来するクラスのstaticメソッドとして拡張関数にアクセスできます。

```java:Java
        KotlinClassA classA = new KotlinClassA();
        KotlinSampleKt.extend(classA);
```

# Nullable

kotlinの便利な機能として`?`を使用したNullable指定があります。

```kotlin:Kotlin
class KotlinOptional {
    var nullableString:String? = null
    var nonNullString:String = "not null!"
}
```
これらはJavaからは取得する場合は代わりはありません

```java:Java
        KotlinOptional optional = new KotlinOptional();
        String nonnull = optional.getNonNullString();
        String nullable = optional.getNullableString();
```

ただ、Nullableではない変数にnullを代入しようとするとその時点で`NullPointerException`がthrowされます。

上記のようにStringだとJavaから見て`?`のある無しで違いが見られませんでしたがIntの場合は

```kotlin:Kotlin
class KotlinOptional2 {
    var nullableInt:Int? = null
    var nonNullInt:Int = 1
}
```


![MainActivity_java_-_kotlin-java-sample_-____Documents_github_kotlin-java-sample_.png](https://qiita-image-store.s3.amazonaws.com/0/8308/1fc569ac-91dc-f2a2-507f-a926e5a7e196.png "MainActivity_java_-_kotlin-java-sample_-____Documents_github_kotlin-java-sample_.png")


nonNullの場合は`int`型でnullableの場合は`Integer`型なんですね。へぇー。

# まとめ

kotlinでの実装もJavaから問題なくアクセスできるようで、安心して導入できますね。