Java - オブジェクトの比較(==、equals、Comparable、Comparator)

Javaで次のようにoperatorまたはメソッドでオブジェクトを比較することができます。

  • ==!= 演算子
  • equals()
  • Objects.equlas()
  • Comparable
  • Comparator

==、!= 演算子

==!=演算子と同じオブジェクトであるか、他のオブジェクトであるかを比較することができます。 オブジェクトが持っているvalueを比較するのではなく、オブジェクトが保存されているメモリアドレスを比較することに注意する必要があります。

次のようにPrimitive typeを比較する際はvalueのみを比較します。

int a = 10;
int b = 10;
int c = 11;

System.out.println(a == b);
System.out.println(a != b);
System.out.println(a == c);

Output:

true
false
false

しかし、Primitive typeではなく、Objectを比較する際valueがなく、Objectのメモリアドレスを比較します。

たとえば、以下のように二つのIntegerオブジェクトを生成しました。 2つのオブジェクトのメモリアドレスは異なるため、結果はfalseになります。

Integer a = new Integer(10);
Integer b = new Integer(10);

System.out.println(a == b);

Output:

false

しかし、次のコードの結果はtrueになります。理由は、両方のオブジェクトは、メモリのアドレスが同じだからです。

Integer a = Integer.valueOf(10);
Integer b = Integer.valueOf(10);

System.out.println(a == b);

Output:

true

次のコードは、 Integer.javavalueOf(int i)です。コードを見れば、キャッシュされているオブジェクトがあるとき、新たに生成せずに、以前に作成したオブジェクトを返すように実装されています。 このため、上記の2つのオブジェクトのメモリアドレスが同じ値を指すされました。

// Integer.java
public static Integer valueOf(int i) {
    if (i >= IntegerCache.low && i <= IntegerCache.high)
        return IntegerCache.cache[i + (-IntegerCache.low)];
    return new Integer(i);
}

したがって、オブジェクトの比較に ==を使用することは、予期せぬ結果をもたらすことができます。 必ず使用する必要が場合、このような部分に注意を払う必要があります。

equals()

equals()を利用すると、オブジェクトのvalueを比較することができます。

Integer a = new Integer(10);
Integer b = new Integer(10);

System.out.println(a.equals(b));

Output:

true

Integer.javaequals()コードを見ると、オブジェクトと引数として渡されるオブジェクトのvalueを比較するように実装されています。

public final class Integer extends Number implements Comparable<Integer> {
  ....

  public boolean equals(Object obj) {
      if (obj instanceof Integer) {
          return value == ((Integer)obj).intValue();
      }
      return false;
  }
}

自分が直接定義したクラスのオブジェクトを比較したい場合は、このように equals()を直接実装してくれるとします。

Objects.equals()

Javaは Objects.equals()というメソッドも提供しています。

オブジェクトの equals()を使用するのと同じ結果を返します。

Integer a = new Integer(10);
Integer b = new Integer(11);

System.out.println(Objects.equals(a, b));

Output:

false

クラスの equals()と相違点は、 Objects.javaのメソッドを見ると、null checkコードがあるので、 NullPointerExceptionは発生しません。

// Objects.java
public static boolean equals(Object a, Object b) {
    return (a == b) || (a != null && a.equals(b));
}

Comparable

次のようなComparableインタフェースをクラスにimplementsして比較することができます。

public interface Comparable<T> {
    public int compareTo(T o);
}

compareTo()は比較するオブジェクトが同じか、大きいか、小さいかを比較して0、負、正を戻すことができます。

次のようにStringを持っているTextという名前のクラスを定義しました。 Comparableをimplementsして compareTo()と呼ばれるメソッドをオーバーライドしました。

public class Text implements Comparable<Text> {
    private String mText;

    public Text(String text) {
        mText = text;
    }

    public String getText() {
        return mText;
    }

    @Override
    public int compareTo(Text right) {
        return mText.compareTo(right.getText());
    }
}

次のように使用することができます。

Text text1 = new Text("aaa");
Text text2 = new Text("aaa");
System.out.println(text1.compareTo(text2));

Output:

0

Comparableは、オブジェクトをSortingするときに使用されます。

Comparator

ComparatorもComparableと似ています。 違いは、Comparatorインターフェイスではなく、オブジェクトとして作成することです。

次のようにオブジェクトを整列するときComparatorを使用することができます。 sort()で引数として渡され、内部でオブジェクトが同じである、大きいか、小さいか比較するのに使用します。 例では、オブジェクトのアドレスを比較するのではなく、文字列の長さを比較しました。

List<String> strings = new ArrayList<>();
strings.add("This code is free software");
strings.add("you can redistribute it");
strings.add("under the terms of the GNU General Public License version 2 only");

// sorting
Collections.sort(strings, new Comparator<String>() {
    @Override
    public int compare(String s1, String s2) {
        return s1.length() - s2.length();
    }
});

System.out.println();
for (String str : strings) {
    System.out.println(str);
}

Output:

you can redistribute it
This code is free software
under the terms of the GNU General Public License version 2 only
codechachaCopyright ©2019 codechacha