KotlinのAny型について

採用はこちら

Any は Kotlinにおけるすべての non-null 型の共通上位型(トップ型の一つ)です。

Kotlinの型システムでは、すべての nullを含まない型Any の下に位置します。

例えば次のような型はすべて Any の下位型です。

  • String
  • Int
  • Boolean
  • List
  • 自作クラス
val a: Any = "Hello"
val b: Any = 100
val c: Any = true

このように Any 型の変数には、さまざまな型の値を代入できます。

目次

Any と Any? の違い

Kotlinでは null安全(null-safety) が型システムに組み込まれています。

そのため、AnyAny? は明確に区別されます。

意味
Anyすべての non-null 型
Any?null を含むすべての型

例えば次のコードは有効です。

val a: Any = "Hello"

しかし Any 型には null を代入できません。

val b: Any = null   // コンパイルエラー

一方、Any?null を許容します。

val c: Any? = null
val d: Any? = "Hello"

つまり Kotlin の型階層では

  • Any は non-null 型の共通上位型
  • Any? は null を含むすべての型の共通上位型

という関係になります。

Any が持つ基本メソッド

Any には次の3つの基本メソッドが定義されています。

open operator fun equals(other: Any?): Boolean
open fun hashCode(): Int
open fun toString(): String

それぞれの役割は次の通りです。

equals

オブジェクトの等価比較を行うメソッドです。

val a = "Hello"
val b = "Hello"

println(a.equals(b))  // true

Kotlinでは通常、equals() を直接呼ぶのではなく == を使います。

println(a == b)

==null-safe な構造的等価比較であり、概念的には次のような処理になります。

もし a が null なら b も null かを確認する  
a が null でなければ a.equals(b) を呼ぶ

hashCode

オブジェクトのハッシュ値を返します。

HashMapHashSet などのコレクションで使用されます。

val str = "Hello"
println(str.hashCode())

toString

オブジェクトの文字列表現を返します。

data class User(val name: String)

val user = User("Taro")
println(user.toString())

出力例

User(name=Taro)

Any 型の基本的な使い方

異なる型の値を扱う

Any を使うと、異なる型の値を一つのコレクションで扱えます。

val list: List<Any> = listOf(
    "Hello",
    100,
    true
)

汎用的な関数の引数として使う

fun printValue(value: Any) {
    println(value)
}

printValue("Hello")
printValue(100)

このように Any を使うと、さまざまな型の値を受け取れる関数を作れます。

Any 型の値の型を判定する方法

Any 型の値は具体的な型が不明なため、処理を行う前に型を判定することがよくあります。

Kotlinでは is 演算子を使います。

fun checkType(value: Any) {
    if (value is String) {
        println("文字列です")
    }
}

スマートキャスト

Kotlinでは is を使って型判定をすると、そのブロック内では自動的に型が確定します。

これを スマートキャスト と呼びます。

fun printLength(value: Any) {
    if (value is String) {
        println(value.length)
    }
}

明示的なキャストを書く必要がありません。

when と Any の組み合わせ

Any 型は when 式と組み合わせて使われることが多いです。

fun printType(value: Any) {
    when (value) {
        is String -> println("String型")
        is Int -> println("Int型")
        is Boolean -> println("Boolean型")
        else -> println("その他の型")
    }
}

このように型ごとの処理を分岐できます。

Any とジェネリクス

Kotlinのジェネリクスでは、型パラメータ T のデフォルト上限は Any? です。

fun <T> printValue(value: T) {
    println(value)
}

これは概念的には次の宣言と同じ意味になります。

fun <T : Any?> printValue(value: T)

つまり、型引数には null を含む型も指定できます。

null を禁止する場合

型パラメータに null を含めたくない場合は、上限を Any にします。

fun <T : Any> printValue(value: T) {
    println(value)
}

この場合 Tnon-null 型のみになります。

Java の Object との違い

Any は Java の Object に近い役割を持ちますが、完全に同じではありません。

項目Kotlin AnyJava Object
nullabilitynullを含まない参照として null を代入可能
型安全null を型で区別する言語仕様では区別しない
役割non-null 型の共通上位型参照型の基本ルート

Kotlinでは AnyAny? に分けることで、コンパイル時に null エラーを防ぎやすくなっています。

Any を使う代表的な場面

型が決まっていないデータを扱う

ログ出力やデバッグ用の関数などで使われます。

fun log(value: Any) {
    println(value)
}

動的データを扱う場合

例えば JSON のように型が混在するデータでは Any が使われることがあります。

val map: Map<String, Any?>

JSONでは null が入る可能性があるため、実際には Any? を使うケースが多くなります。

Any を使うときの注意点

Any は便利ですが、使いすぎると型安全性が下がります。

例えば次のコードです。

val value: Any = "Hello"

この場合、値の型はコンパイル時には確定しません。

そのため、可能であれば 具体的な型を使う方が安全です。

val value: String = "Hello"

Any本当に型が分からない場合のみ使用するのが一般的です。

まとめ

Kotlinの Any 型には次の特徴があります。

  • Kotlinの すべての non-null 型の共通上位型
  • Javaの Object に近い役割を持つ
  • equals / hashCode / toString を持つ
  • null を含めたい場合は Any? を使う
  • 型判定には iswhen を使う
  • ジェネリクスの上限指定にも使われる

Any は Kotlin の型システムを理解するうえで非常に重要な型です。

ただし、実際のコードでは 可能な限り具体的な型を使うことが推奨されています。

以上、KotlinのAny型についてでした。

最後までお読みいただき、ありがとうございました。

よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!
目次