JavaとScalaで比較

デバッグ中に珍しく参照の比較をしたくなったもので、メモ。

基本

Java

// 値の比較
Hoge hoge = new Hoge();
Hoge fuga = new Fuga();

System.out.println(hoge.equals(fuga)? "値が一致している" : "値が異なる");
// 参照の比較
Hoge hoge = new Hoge();
Hoge fuga = hoge;

System.out.println(hoge == fuga? "参照が一致している" : "参照が異なる");

Scala

// 値の比較
val hoge = new Hoge()
val fuga = new Fuga()

System.out.println(if(hoge == fuga) { "値が一致している" } else { "値が異なる" })
// 参照の比較
val hoge = new Hoge()
val fuga = hoge

System.out.println(if(hoge eq fuga) { "参照が一致している" } else { "参照が異なる" })

Scalaでは==が値の比較となっている(というか、equalsメソッドを参照している)ため、参照を比較したい場合は特にeqメソッドを利用する必要があります。

参照の同一性が気になるのは副作用のあるメソッドを呼び出す場合だと思うんですが、Scalaは関数型で副作用がないよう設計するのが常道であるため、Java以上に参照比較の利用場面は少ないんじゃないでしょうか。

ちょっと特殊なもの

Javaの参照比較で注意が必要なのはString型の場合ですね。

String hoge = "hoge";
String fuga = "hoge";

System.out.println(hoge == fuga? "参照が一致している" : "参照は一致していない");
// →実は参照が一致している

Javaではリテラルで記述された同一内容の文字列型はすべて同じオブジェクトとなるようで、その結果リテラルで記述された同一の文字列は参照比較でもtrueが返ってきてしまいます。

もちろん、明示的に新しいオブジェクトを作ってやれば参照はズレます。

String hoge = new String("hoge");
String fuga = new String("hoge");

System.out.println(hoge == fuga? "参照が一致している" : "参照は一致していない");
// →今度は参照が一致しない

参考