等価性
Kotlinには、2種類の等価性があります:
- _構造的_等価性 (
==
) -equals()
関数のチェック - _参照_等価性 (
===
) - 2つの参照が同じオブジェクトを指しているかどうかのチェック
構造的等価性
構造的等価性は、2つのオブジェクトが同じ内容または構造を持っているかどうかを検証します。構造的等価性は、==
演算子とその否定の!=
によってチェックされます。 慣例として、a == b
のような式は次のように翻訳されます:
a?.equals(b) ?: (b === null)
a
がnull
でない場合、equals(Any?)
関数を呼び出します。それ以外の場合(a
がnull
の場合)は、b
が参照的にnull
と等しいかどうかをチェックします:
fun main() {
var a = "hello"
var b = "hello"
var c = null
var d = null
var e = d
println(a == b)
// true
println(a == c)
// false
println(c == e)
// true
}
null
と比較する場合、コードを明示的に最適化する意味がないことに注意してください: a == null
は自動的にa === null
に変換されます。
Kotlinでは、equals()
関数はすべてのクラスがAny
クラスから継承します。デフォルトでは、equals()
関数は参照等価性を実装します。しかし、Kotlinのクラスはequals()
関数をオーバーライドしてカスタムの等価性ロジックを提供し、このようにして構造的等価性を実装できます。
値クラス (Value classes) とデータクラス (data classes) は、equals()
関数を自動的にオーバーライドする2つの特定のKotlin型です。そのため、デフォルトで構造的等価性を実装します。
ただし、データクラスの場合、親クラスでequals()
関数がfinal
とマークされている場合、その動作は変更されません。
明確に、非データクラス(data
修飾子で宣言されていないクラス)は、デフォルトではequals()
関数をオーバーライドしません。代わりに、非データクラスはAny
クラスから継承された参照等価性の動作を実装します。構造的等価性を実装するには、非データクラスはequals()
関数をオーバーライドするためのカスタム等価性ロジックを必要とします。
カスタムの等価性チェック実装を提供するには、equals(other: Any?): Boolean
関数をオーバーライドします:
class Point(val x: Int, val y: Int) {
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (other !is Point) return false
// 構造的等価性のためにプロパティを比較
return this.x == other.x && this.y == other.y
}
}
equals()
関数をオーバーライドする際は、等価性とハッシュ化の整合性を保ち、これらの関数の適切な動作を保証するために、hashCode()関数もオーバーライドする必要があります。
同じ名前で異なるシグネチャ(例: equals(other: Foo)
) を持つ関数は、==
および!=
演算子による等価性チェックには影響しません。
構造的等価性は、Comparable<...>
インターフェースによって定義される比較とは関係ないため、カスタムのequals(Any?)
実装のみが演算子の動作に影響を与える可能性があります。
参照等価性
参照等価性は、2つのオブジェクトのメモリ上のアドレスを検証し、それらが同じインスタンスであるかどうかを判断します。
参照等価性は、===
演算子とその否定の!==
によってチェックされます。a === b
は、a
とb
が同じオブジェクトを指している場合にのみtrueと評価されます:
fun main() {
var a = "Hello"
var b = a
var c = "world"
var d = "world"
println(a === b)
// true
println(a === c)
// false
println(c === d)
// true
}
ランタイムでプリミティブ型(例: Int
)によって表現される値の場合、===
等価性チェックは==
チェックと同等です。
Kotlin/JSでは、参照等価性の実装が異なります。等価性に関する詳細については、Kotlin/JSドキュメントを参照してください。
浮動小数点数の等価性
等価性チェックのオペランドが静的にFloat
またはDouble
(null許容かどうかにかかわらず)であることが判明している場合、そのチェックはIEEE 754 浮動小数点算術標準に従います。
オペランドが静的に浮動小数点数として型付けされていない場合、動作は異なります。これらのケースでは、構造的等価性が実装されます。結果として、静的に浮動小数点数として型付けされていないオペランドでのチェックは、IEEE標準とは異なります。このシナリオでは:
NaN
はそれ自身と等しいNaN
は他のどの要素(POSITIVE_INFINITY
を含む)よりも大きい-0.0
は0.0
と等しくない
詳細については、浮動小数点数の比較を参照してください。
配列の等価性
2つの配列が同じ要素を同じ順序で持っているかどうかを比較するには、contentEquals()
を使用します。
詳細については、配列の比較を参照してください。