ざっくり結論
== は「同じ実体(同じ場所)か」を比べる演算子、equals は「中身(値)が同じか」を比べるメソッドです。プリミティブでは == が値比較、参照型(オブジェクト)では == が参照比較(同一性)、equals は値比較(等価性)になります。どちらを使うかは「何を同じとみなしたいか」で決まります。
プリミティブと参照型での違い
プリミティブ(int, double, boolean など)
プリミティブは「値そのもの」なので、== は値の比較です。equals はありません。
int a = 10, b = 10, c = 20;
System.out.println(a == b); // true(値が同じ)
System.out.println(a == c); // false
Java参照型(String, 自作クラスなど)
- == は「同じインスタンス(同じ参照)か」を比較します。
- equals は「値や意味が同じか」を比較します(クラスの実装次第)。
String s1 = new String("abc");
String s2 = new String("abc");
System.out.println(s1 == s2); // false(別インスタンス)
System.out.println(s1.equals(s2)); // true(文字列内容が同じ)
Javaequals の設計意図(重要ポイントの深掘り)
equals は「何をもって同じとするか」を型に刻む
値オブジェクトでは equals をオーバーライドして、等価の定義(比較に使うフィールド)を明確にします。HashSet/HashMap で正しく扱うには equals と hashCode を同じ基準で実装することが必須です。
import java.util.Objects;
public final class Email {
private final String value;
public Email(String raw) {
var v = raw == null ? "" : raw.trim().toLowerCase();
if (!v.contains("@")) throw new IllegalArgumentException();
this.value = v;
}
@Override public boolean equals(Object o) {
return o instanceof Email e && Objects.equals(value, e.value);
}
@Override public int hashCode() { return Objects.hash(value); }
}
Javaequals を用意すると、「中身が同じなら同じ」と安全に言えるようになります。== は「同じインスタンスか」しか分かりません。
よくある混乱ポイントと注意例
String の == と equals
String の equals は内容比較、== は参照比較。リテラルは「文字列プール」で同一参照になることがあり、誤って true になるケースがあるため、内容比較は常に equals を使います。
String a = "abc";
String b = "abc";
System.out.println(a == b); // true(同一プール参照になることが多い)
System.out.println(a.equals(b)); // 常に内容比較(こちらを使う)
Javaラッパー型(Integer など)の == と equals
オートボクシングやキャッシュ(例えば Integer は -128〜127 をキャッシュ)により、== が期待通りに動かないことがあります。値比較は equals を使うのが安全です。
Integer x = 127, y = 127;
System.out.println(x == y); // true(キャッシュ参照が同じ)
Integer p = 128, q = 128;
System.out.println(p == q); // false になり得る(別インスタンス)
System.out.println(p.equals(q)); // true(値比較)
JavaBigDecimal の equals と compareTo
BigDecimal はスケールも含めて equals 比較します。値の大小だけ比較したいなら compareTo を使います。
var a = new java.math.BigDecimal("1.0");
var b = new java.math.BigDecimal("1.00");
System.out.println(a.equals(b)); // false(スケール違い)
System.out.println(a.compareTo(b)); // 0(数値として等しい)
Java配列は equals が参照比較
配列の equals は Object の実装を継承し、参照比較になります。内容比較には Arrays.equals/Arrays.deepEquals を使います。
int[] u = {1,2}, v = {1,2};
System.out.println(u.equals(v)); // false(参照比較)
System.out.println(java.util.Arrays.equals(u, v)); // true(内容比較)
Java== を使うべき場面と equals を使うべき場面
== が適切な場面
- プリミティブの比較
- 参照が同一かどうか(同じインスタンスか)の判定
- enum(同一インスタンスが保証される)では == で等価判定してよい
enum Color { RED, BLUE }
Color c1 = Color.RED, c2 = Color.RED;
System.out.println(c1 == c2); // true(enumはインスタンスが一意)
Javaequals が適切な場面
- 参照型の値比較(文字列、値オブジェクト、ラッパー型など)
- コレクションの contains、Map のキー比較など「等価性」を前提とする操作
var list = java.util.List.of("a", "b");
System.out.println(list.contains(new String("a"))); // true(equalsで内容比較)
Javanull と安全な書き方
NullPointerException を避ける equals の書き方
呼び出し側が null の可能性があるときは、定数側から equals を呼ぶ、または Objects.equals を使うと安全です。
String s = null;
System.out.println("x".equals(s)); // false(安全)
System.out.println(java.util.Objects.equals(s, "x")); // false(安全)
Java例題で理解を固める
例 1: 値オブジェクトの比較
Email e1 = new Email("A@b.com");
Email e2 = new Email("a@B.COM"); // 正規化で同値になる設計
System.out.println(e1 == e2); // false(別インスタンス)
System.out.println(e1.equals(e2)); // true(値が同じ)
Java例 2: 参照同一性が必要な判定
class Session { /* ... */ }
Session s1 = new Session();
Session s2 = s1;
System.out.println(s1 == s2); // true(同じセッション実体)
Java仕上げのアドバイス(重要部分のまとめ)
- プリミティブは == で値比較、参照型は「同一性なら ==」「等価性なら equals」。
- 文字列やラッパー型の値比較は必ず equals。配列の内容比較は Arrays.equals。
- 値オブジェクトを設計するときは equals/hashCode をセットで実装し、「何を同じとするか」を型に刻む。
- null 安全のために定数側から equals を呼ぶか、Objects.equals を使う。
