Khi so sánh các đối tượng trong Java, bạn kiểm tra ngữ nghĩa , so sánh kiểu và trạng thái xác định của các đối tượng với:
- chính nó (cùng một trường hợp)
- chính nó (sao chép hoặc bản sao tái tạo)
- các đối tượng khác thuộc các loại khác nhau
- các đối tượng khác cùng loại
null
Quy tắc:
- Đối xứng :
a.equals(b) == b.equals(a)
equals()
luôn mang lại true
hoặc false
, nhưng không bao giờ là một NullpointerException
, ClassCastException
hoặc bất kỳ thứ gì khác có thể ném
So sánh:
- Kiểm tra kiểu : cả hai trường hợp cần phải cùng kiểu, nghĩa là bạn phải so sánh các lớp thực tế để có sự bình đẳng. Điều này thường không được triển khai chính xác, khi các nhà phát triển sử dụng
instanceof
để so sánh kiểu (chỉ hoạt động miễn là không có lớp con và vi phạm quy tắc đối xứng khi A extends B -> a instanceof b != b instanceof a)
.
- Kiểm tra ngữ nghĩa của trạng thái xác định : Đảm bảo bạn hiểu trạng thái nào mà các cá thể được xác định. Người đó có thể được xác định bằng số an sinh xã hội của họ, nhưng không phải bằng màu tóc (có thể nhuộm), tên (có thể thay đổi) hoặc tuổi (thay đổi liên tục). Chỉ với các đối tượng giá trị, bạn mới nên so sánh trạng thái đầy đủ (tất cả các trường không phải là trường tạm thời), nếu không chỉ kiểm tra những gì xác định cá thể.
Đối với Person
lớp học của bạn :
public boolean equals(Object obj) {
// same instance
if (obj == this) {
return true;
}
// null
if (obj == null) {
return false;
}
// type
if (!getClass().equals(obj.getClass())) {
return false;
}
// cast and compare state
Person other = (Person) obj;
return Objects.equals(name, other.name) && Objects.equals(age, other.age);
}
Loại tiện ích chung, có thể tái sử dụng:
public final class Equals {
private Equals() {
// private constructor, no instances allowed
}
/**
* Convenience equals implementation, does the object equality, null and type checking, and comparison of the identifying state
*
* @param instance object instance (where the equals() is implemented)
* @param other other instance to compare to
* @param stateAccessors stateAccessors for state to compare, optional
* @param <T> instance type
* @return true when equals, false otherwise
*/
public static <T> boolean as(T instance, Object other, Function<? super T, Object>... stateAccessors) {
if (instance == null) {
return other == null;
}
if (instance == other) {
return true;
}
if (other == null) {
return false;
}
if (!instance.getClass().equals(other.getClass())) {
return false;
}
if (stateAccessors == null) {
return true;
}
return Stream.of(stateAccessors).allMatch(s -> Objects.equals(s.apply(instance), s.apply((T) other)));
}
}
Đối với Person
lớp của bạn , sử dụng lớp tiện ích này:
public boolean equals(Object obj) {
return Equals.as(this, obj, t -> t.name, t -> t.age);
}