タイトル通りの内容ですが、地味に初めて知ったので備忘録として。
Dateクラスを例として
とあるPull Requestの中に以下のような関数がありました。
引数に渡されたdate
を現在時刻と比較し、期限を過ぎているかどうかを判定する関数です。
fun isExpired(date: Date): Boolean { return date > Date() }
結果として、この関数の比較結果が正しいことは分かったのですが、Date
オブジェクト同士を比較演算子で直接比較できていることに個人的には違和感がありました。
以下では、この件について調べた内容を記載しています。
比較演算子はcompareTo()
メソッドに変換される?
IDEで>
の宣言を参照すると、Date
クラス内のcompareTo()
メソッドが表示されました。
このcompareTo()
メソッドはComparable
インタフェースの実装です。
(できれば@override
アノテーションを付けておいてほしい…)
public class Date implements Serializable, Cloneable, Comparable<Date> { ... public int compareTo(Date anotherDate) { long thisTime = getMillisOf(this); long anotherTime = getMillisOf(anotherDate); return (thisTime < anotherTime ? -1 : (thisTime == anotherTime ? 0 : 1)); } ... }
このことから、Kotlinの比較演算子は、比較対象のクラスのcompareTo()
メソッドに変換されるであろうことが分かりました。
ただ、compareTo()
メソッドの戻り値はInt
型で、単純な変換ではBoolean
型にならずコンパイルエラーになるはずなので、Kotlinの比較演算子の変換についてさらに調べてみました。
(この時点では「何故after()
メソッドではなくcompareTo()
メソッドなんだろう?」と思っていました笑)
比較演算子は「compareTo()
メソッド + 期待される値の範囲」の組み合わせに変換される
公式ドキュメントの演算子オーバーロードの項目を確認すると、Kotlinの比較演算子は、比較対象のクラスの「compareTo()
メソッド + 期待される値の範囲」の組み合わせに変換されるようでした。
試しに冒頭の関数のバイトコードをデコンパイルしてみたところ、確かに上記の表の式の形に変換されていました。
public boolean isExpired(@NotNull Date date) { Intrinsics.checkNotNullParameter(date, "date"); return date.compareTo(new Date()) > 0; }
結果として、KotlinではComparable
インタフェースを実装したクラスのオブジェクト同士を比較演算子で直接比較できることが分かりました。