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の参照渡しについてでした。
最後までお読みいただき、ありがとうございました。










