2008-09-23 38 views
9

Câu hỏi này liên quan cụ thể đến việc ghi đè phương thức equals() cho các đối tượng có số lượng trường lớn. Trước tiên, hãy để tôi nói rằng đối tượng lớn này không thể chia nhỏ thành nhiều thành phần mà không vi phạm nguyên tắc OO, vì vậy hãy nói với tôi rằng "không có lớp nào có nhiều hơn x trường" sẽ không giúp được gì.Java bằng(): để phản ánh hoặc không phản ánh

Tiếp tục, sự cố đã thành hiện thực khi tôi quên kiểm tra một trong các trường cho sự bình đẳng. Vì vậy, phương pháp equals của tôi là không chính xác. Sau đó, tôi nghĩ sử dụng sự phản chiếu:

--code removed because it was too distracting-- 

Mục đích của bài đăng này không nhất thiết phải tái cấu trúc mã (nhưng không phải mã tôi đang sử dụng), nhưng thay vào đó hãy nhập liệu có hay không là một ý tưởng tốt.

Ưu điểm:

  • Nếu một lĩnh vực mới được thêm vào, nó sẽ tự động bao gồm
  • Phương pháp này là nhiều hơn nữa ngắn gọn hơn 30 nếu phát biểu

Nhược điểm:

  • Nếu một trường mới được thêm vào, trường này sẽ tự động được bao gồm, đôi khi điều này là không mong muốn
  • Hiệu suất: Điều này phải chậm hơn, tôi không cảm thấy cần phải phá vỡ sơ lược
  • Tìm kiếm các trường nhất định để bỏ qua trong so sánh là một chút xấu xí

Bất kỳ suy nghĩ nào?

Trả lời

13

Nếu bạn muốn đưa vào danh sách trắng vì lý do hiệu suất, hãy xem xét sử dụng chú thích để cho biết cần so sánh các trường nào. Ngoài ra, triển khai này sẽ không hoạt động nếu các trường của bạn không triển khai tốt cho equals().

P.S. Nếu bạn đi theo tuyến đường này cho equals(), đừng quên làm điều gì đó tương tự cho hashCode().

P.P.S. Tôi tin rằng bạn đã xem xét HashCodeBuilderEqualsBuilder.

+0

Tất cả các trường là chuỗi hoặc nguyên thủy @ P.S. Đã làm điều đó, nhưng nó không làm tổn thương để nhắc nhở mọi người! @ P.P.S. Tôi biết phải có thứ gì đó ở ngoài kia. Tôi đã sử dụng ToStringBuilder, tôi không có ý tưởng làm thế nào tôi bỏ qua những người. Câu hỏi thực sự là phản ánh hoặc không phản ánh. – oreoshake

+0

Tùy thuộc vào những gì bạn cho là có khả năng: thêm trường và quên thêm trường bằng() hoặc thêm trường bạn không muốn và/hoặc không thể sử dụng trong so sánh tự động, mặc dù sử dụng chú thích có thể trợ giúp . Bạn có thể xem xét một cái gì đó như flexjson và so sánh đầu ra của từng đối tượng. –

+0

Những người xây dựng này khá thú vị. –

1

Bạn luôn có thể chú thích các trường bạn làm/không muốn theo phương thức equals của bạn, đó phải là một thay đổi đơn giản và đơn giản đối với nó.

Hiệu suất rõ ràng liên quan đến tần suất đối tượng thực sự được so sánh, nhưng nhiều khung công tác sử dụng bản đồ băm, vì vậy, bạn có thể sử dụng bằng nhiều hơn bạn nghĩ.

Ngoài ra, nói về bản đồ băm, bạn có cùng một vấn đề với phương pháp hashCode.

Cuối cùng, bạn có thực sự cần phải so sánh tất cả các trường cho sự bình đẳng không?

+0

Tôi thực sự bỏ lỡ, chúng tôi có một phương pháp hashcode/equals chỉ sử dụng ID của hồ sơ (từ một db) và vì điều này luôn là duy nhất phương thức hashCode/equals chỉ so sánh các ID. Nhưng chúng ta cần phải kiểm tra xem các đối tượng có tương đương hay không, mỗi trường đều giống nhau. – oreoshake

0

Nếu bạn có quyền truy cập vào tên của các trường, tại sao bạn không làm cho tiêu chuẩn là các trường bạn không muốn bao gồm luôn bắt đầu bằng "cục bộ" hoặc "nochk" hoặc thứ gì đó tương tự.

Sau đó, bạn liệt kê tất cả các trường bắt đầu bằng mã này (mã không quá xấu xí sau đó).

Tôi không nghi ngờ nó chậm hơn một chút. Bạn cần phải quyết định xem bạn có muốn trao đổi các cập nhật dễ dàng với tốc độ thực thi hay không.

+1

Tôi nghĩ rằng việc thêm quy ước cho một cái gì đó như thế này sẽ làm giảm khả năng đọc không cần thiết. – oreoshake

1

Bạn có một vài lỗi trong mã của mình.

  1. Bạn không thể giả định rằng thisobj là cùng một lớp. Thật vậy, nó được cho phép rõ ràng cho obj là bất kỳ lớp nào khác. Bạn có thể bắt đầu với if (! obj instanceof myClass) return false; tuy nhiên đây là vẫn không chính xácobj có thể là một phân lớp của this với các trường bổ sung có thể quan trọng.
  2. Bạn phải hỗ trợ null giá trị cho obj với một đơn giản if (obj == null) return false;
  3. Bạn không thể đối xử với null và chuỗi rỗng như bằng nhau. Thay vào đó, hãy xử lý null đặc biệt. Cách đơn giản nhất ở đây là bắt đầu bằng cách so sánh Field.get(obj) == Field.get(this). Nếu cả hai đều bằng nhau hoặc cả hai xảy ra để trỏ đến cùng một đối tượng, điều này là nhanh. (Lưu ý: Đây cũng là một tối ưu hóa, mà bạn cần vì đây là một thói quen chậm.) Nếu điều này không thành công, bạn có thể sử dụng nhanh if (Field.get(obj) == null || Field.get(this) == null) return false; để xử lý các trường hợp chính xác là null. Cuối cùng, bạn có thể sử dụng thông thường equals().
  4. Bạn không sử dụng foundMismatch

Tôi đồng ý với Hank rằng [HashCodeBuilder][1][EqualsBuilder][2] là một cách tốt hơn để đi. Thật dễ dàng để duy trì, không nhiều mã soạn sẵn, và bạn tránh tất cả những vấn đề này.

2

Dưới đây là một ý nghĩ nếu bạn đang lo lắng về:

1/Forgetting để cập nhật hàng loạt lớn của bạn của if- báo cáo để kiểm tra bình đẳng khi bạn thêm/xóa một trường.

2/Hiệu suất thực hiện việc này bằng phương thức equals().

Hãy thử các cách sau:

a/Hoàn nguyên về sử dụng chuỗi dài các câu lệnh if trong phương thức equals().

b) Có một hàm duy nhất chứa danh sách các trường (trong mảng Chuỗi) và sẽ kiểm tra danh sách đó với thực tế (tức là trường được phản ánh). Nó sẽ ném một ngoại lệ nếu chúng không khớp.

c/Trong hàm khởi tạo của bạn cho đối tượng này, có một cuộc gọi chạy một lần được đồng bộ hóa với hàm này (tương tự như mẫu đơn). Nói cách khác, nếu đây là đối tượng đầu tiên được xây dựng bởi lớp này, hãy gọi hàm kiểm tra được mô tả trong (b) ở trên.

Ngoại lệ sẽ hiển thị ngay lập tức khi bạn chạy chương trình của mình nếu bạn chưa cập nhật các câu lệnh if để khớp với các trường được phản ánh; sau đó bạn sửa các câu lệnh if và cập nhật danh sách trường từ (b) ở trên.

Xây dựng các đối tượng tiếp theo sẽ không thực hiện kiểm tra này và phương thức equals() của bạn sẽ chạy với tốc độ tối đa có thể. Hãy thử như tôi có thể, tôi đã không thể tìm thấy bất kỳ vấn đề thực sự với cách tiếp cận này (tâm trí lớn hơn có thể tồn tại trên StackOverflow) - có thêm một điều kiện kiểm tra trên mỗi đối tượng xây dựng cho hành vi chạy một lần nhưng có vẻ như khá nhỏ.

Nếu bạn cố gắng hết sức, bạn vẫn có thể nhận được các tuyên bố của mình bằng các trường trường và danh sách trường nhưng ngoại lệ sẽ đảm bảo danh sách trường của bạn khớp với trường được phản ánh và bạn chỉ cần đảm bảo cập nhật -Báo cáo và danh sách lĩnh vực cùng một lúc.

5

Nếu bạn đi phương pháp phản xạ, EqualsBuilder vẫn là bạn của bạn:

public boolean equals(Object obj) { 
    return EqualsBuilder.reflectionEquals(this, obj); 
} 
1

Bạn có thể sử dụng chú thích để loại trừ các lĩnh vực từ việc kiểm tra

ví dụ

@IgnoreEquals 
String fieldThatShouldNotBeCompared; 

Và sau đó tất nhiên bạn kiểm tra sự hiện diện của chú thích theo phương pháp tương đương chung.

9

Sử dụng Eclipse, FFS!

Xóa hashCode và bằng các phương thức bạn có.

Nhấp chuột phải vào tệp.

Chọn nguồn-> Tạo mã băm và bằng ...

Xong! Không còn lo lắng về sự phản chiếu.

Lặp lại cho mỗi trường được thêm vào, bạn chỉ cần sử dụng khung nhìn phác thảo để xóa hai phương thức của bạn và sau đó để Eclipse tự tạo chúng.

+2

Trong khi dễ dàng hơn bằng cách viết phương pháp bằng tay, điều này chia sẻ nhược điểm chính của cả hai phương pháp phản chiếu và mã hóa bằng tay. Phương pháp này vẫn có thể lỗi thời khi các trường được thêm vào và phương thức không được tạo lại và các trường vẫn có thể được kiểm tra mà không được khi người nào đó tạo lại phương thức và quên xóa séc. –

+0

Đôi khi không có viên đạn ma thuật. Nhưng giải pháp đơn giản nhất thường là cách dễ nhất để đi trong những trường hợp này. – MetroidFan2002