Tìm hiểu về == và equals()

I, So sánh == vs equals()

  • Toán tử == dùng để so sánh memory address: hai biến có trỏ tới cùng 1 object trên memory (heap memory, string pool…) hay không.
  • Phương thức equals() có hai kiểu so sánh:
    • Shallow comparison: mặc định equals() có implement của Object, nó trả về true khi và chỉ khi 2 biến x và y cùng trỏ tới 1 object (x == y return true). Điều này là bởi vì Object không có property nào để định nghĩa state.
    • Deep comparison: class có các property và tiến hành implement equals() dựa trên các property đó.
  • Với các class như Integer, String… equals() đã thực hiện deep comparison tức là các class đó đã tiến hành implement equals() dựa trên so sánh các property của chúng.
  • Chú ý: Nếu 1 class không implement equals() method, equals() của class đó sẽ thừa hưởng từ class cha gần nhất implement equals() method.
  • Ví dụ 1: source code implement equals() method (shallow comparison) trong Object class
1
2
3
public boolean equals(Object obj) {
return (this == obj);
}
  • Ví dụ 2: source code implement equals() method (deep comparison) trong 2 class IntegerString
1
2
3
4
5
6
7
// Integer.java
public boolean equals(Object obj) {
if (obj instanceof Integer) {
return value == ((Integer)obj).intValue();
}
return false;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// String.java
public boolean equals(Object anObject) {
if (this == anObject) {
return true;
}
if (anObject instanceof String) {
String anotherString = (String)anObject;
int n = length();
if (n == anotherString.length()) {
int i = 0;
while (n-- != 0) {
if (charAt(i) != anotherString.charAt(i))
return false;
i++;
}
return true;
}
}
return false;
}

II, Deep comparison

  • Với api object như Integer, String… đã implement equals() method.

  • Chúng thực hiện có deep comparison như mình đã nói ở trên.

  • Ví dụ 3:

1
2
3
4
5
6
7
8
int a = 1000;
Integer b = 1000;
Integer c = new Integer(1000);

a == b // true bởi vì java có cơ chế autoboxing và unboxing nên khi so sánh b sẽ bị unboxing về int.
b == c ? // false bởi vì b và c trỏ tới 2 object khác nhau trên heap.
b.equals(a) ? // true bởi vì b và a cùng giá trị 1000.
c.equals(b) ? // true vì b và c cùng giá trị 1000.
  • Ví dụ 4:
1
2
3
4
5
6
7
8
String a = "abc";
String b = "abc";
String c = new String("abc");

a == b // true bời vì a và b được tạo từ String literals trong String pool trên heap nên chúng sẽ trỏ tới cùng 1 object.
b == c // false bởi vì toán tử new tạo ra 1 object khác không nằm trong String pool trên bộ nhớ heap.
a.equals(b) // true bởi vì a và b có cùng giá trị.
c.equals(b) // true bởi vì a và b có cùng giá trị.

III, Shallow comparison

  • Đối với class tự định nghĩa, nếu không implement equals() thì class đó sẽ lấy implement của Object class.

  • Chúng thực hiện shallow comparison.

  • Ví dụ 5: shallow comparison không override equals() method

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
class Test {

public int val;

public Test(int val){
this.val = val;
}
}

class TestComparator(){

public static void main(String args[]){
Test a = new Test(1000);
Test b = new Test(1000);
a == b // return false bởi vì a và b trỏ đến 2 object khác nhau.
a.equals(b) // return false mặc định equals() cũng so sánh memory address như ==.
}
}
  • Ví dụ 6: deep comparison override equals() method
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
class Test {

private int val;

public Test(int val){
this.val = val;
}

// Deep comparison
public boolean equals(Test b){
return this.val == b.val
}
}

class TestComparator(){

public static void main(String args[]){
Test a = new Test(1000);
Test b = new Test(1000);
a == b // return false bởi vì a và b trỏ đến 2 object khác nhau.
a.equals(b) // return true.
}
}