Kotlinの参照渡しについて

採用はこちら

Kotlinの「参照渡し」は、初学者だけでなく実務経験者でも誤解しやすいテーマです。

結論から述べると、Kotlinでは関数の引数はすべて値渡し(pass by value)です。

ただし、オブジェクトを扱う場合には 「参照という値」 が渡されるため、結果として参照渡しのように見える挙動になります。

本記事では、この仕組みを 概念 → 実例 → 誤解されやすいポイント → 実務での設計指針 の順で整理して解説します。

目次

Kotlinの大原則:引数はすべて「値渡し」

Kotlin(JVM / JS)では、関数呼び出し時に渡される引数は 必ず値のコピー です。

ここで重要なのは、「値」とは何かという点です。

  • 数値や真偽値 → 値そのもの
  • クラス・配列・コレクション → オブジェクトへの参照という値

この違いが、「参照渡しに見える」挙動を生みます。

プリミティブ的な型の例(純粋な値渡し)

fun changeValue(x: Int) {
    x = 10
}

fun main() {
    var a = 5
    changeValue(a)
    println(a) // 5
}

何が起きているか

  • a の値(5)が x にコピーされる
  • x を変更しても、元の a には影響しない

これは典型的な 値渡し です。

※ JVM上では boxing が発生する場合もありますが、「引数が値として渡される」という事実は変わりません。

オブジェクトを渡した場合(参照という値がコピーされる)

class Box(var value: Int)

fun changeBox(box: Box) {
    box.value = 10
}

fun main() {
    val box = Box(5)
    changeBox(box)
    println(box.value) // 10
}

なぜ呼び出し元の値が変わるのか

  • box 変数には Boxオブジェクトへの参照 が格納されている
  • 関数には、その参照が 値としてコピー されて渡る
  • コピー元とコピー先は、同じオブジェクトを指す

そのため、オブジェクトの内部状態(プロパティ)を変更すると、呼び出し元から見える状態も変化します。

これは参照渡しではなく、「参照の値渡し」

参照そのものを差し替えるとどうなるか

fun replaceBox(box: Box) {
    box = Box(10)
}

fun main() {
    val box = Box(5)
    replaceBox(box)
    println(box.value) // 5
}

なぜ影響しないのか

  • 関数の引数 boxローカル変数
  • 参照を別オブジェクトに向け直しても、それは関数内だけの話
  • 呼び出し元の box には影響しない

ここから分かる通り、参照そのものも値として渡されていることが確認できます。

Kotlinに「参照渡し」は存在しない

他言語と比較すると整理しやすくなります。

言語引数の渡し方
Kotlin / Java値渡し(参照も値)
Python値渡し(オブジェクト参照)
C++参照渡しが存在する

Kotlinには、C++のように「変数そのものを別名で扱う」参照渡しは存在しません。

コレクションと参照共有:Mutableかどうかが本質

fun addItem(list: MutableList<Int>) {
    list.add(10)
}

fun main() {
    val list = mutableListOf(1, 2, 3)
    addItem(list)
    println(list) // [1, 2, 3, 10]
}

ポイント

  • MutableList は中身を変更できる
  • 同じリストオブジェクトへの参照が共有されている
  • そのため、変更が呼び出し元にも反映される

List は immutable ではなく「read-only」

ここは非常に誤解されやすい点です。

fun replaceList(list: List<Int>) {
    list = listOf(9, 9, 9) // コンパイルエラー
}

このエラーの理由は

  • 関数引数は暗黙的に val(再代入不可)だから

であり、「List が不変だから」ではありません。

重要な整理

  • List:読み取り専用インターフェース(read-only)
  • 不変(immutable)を保証するものではない
  • 背後の実体が MutableList であれば、別経路から変更される可能性はある

val / var と参照渡しは無関係

val box = Box(5)
box.value = 10 // OK
  • val参照の再代入を禁止するだけ
  • オブジェクトの内部状態を不変にするものではない
box = Box(10) // コンパイルエラー

val = 再代入不可、immutable ではない

安全な設計:data class と copy()

data class User(val name: String, val age: Int)

fun updateUser(user: User): User {
    return user.copy(age = user.age + 1)
}

この設計のメリット

  • 元のオブジェクトを変更しない
  • 副作用がなく予測可能
  • 並行処理・UI状態管理と相性が良い

Kotlinでは、「変更する」よりも 新しい値を返す設計 が推奨されます。

まとめ:Kotlinの参照渡しを一文で言うと

  • Kotlinの引数は すべて値渡し
  • オブジェクトの場合、参照という値がコピーされる
  • そのため状態変更が共有され、参照渡しのように見える
  • 参照の差し替えは呼び出し元に影響しない
  • List は immutable ではなく read-only

以上、Kotlinの参照渡しについてでした。

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

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