2011-11-13 38 views
15

Lý do đằng sau quyết định bao gồm những phương thức này trong java.lang.Object là gì? Sự bình đẳng và băm không có ý nghĩa đối với nhiều lớp.Tại sao bằng và hashCode được xác định trong Object?

Nó sẽ là hợp lý hơn để làm cho hai giao diện:

interface Equalable { 
    boolean equals(Equalable other); 
} 

interface Hashable extends Equalable { 
    int hashCode(); 
} 

Ví dụ định nghĩa HashSet có thể trông như

class HashSet<T extends Hashable> ... 

Nó sẽ ngăn chặn một trong những sai lầm mới bắt đầu phổ biến - sử dụng bộ sản phẩm mà không cần triển khai equals/hashCode.

+0

Hãy xem [tại đây] (http://msmvps.com/blogs/jon_skeet/archive/2008/12/05/redesigning-system-object-java-lang-object.aspx) để có bài viết hay về nội dung nào đó liên quan (bởi Jon Skeet). –

+1

liên kết dường như đã chết. [This] (http://codeblog.jonskeet.uk/2008/12/05/redesigning-system-object-java-lang-object/) có thể là cùng một bài viết. – tkokasih

Trả lời

13

Khi chúng tôi triển khai Interface, chúng tôi inject (or accept) hợp đồng được xác định bởi giao diện.

Equalable & Hashable là hai hợp đồng khác nhau. Nhưng nếu chúng ta xem xét kỹ thì chúng ta sẽ thấy rằng cả hai đều phụ thuộc vào nhau, có nghĩa là chúng là một phần của single interface, giống như EqualableAndHashable.

Bây giờ câu hỏi hiển nhiên là, liệu chúng có phải là một phần của giao diện EqualableAndHashable mới này hay Object không?

Hãy tìm hiểu. Chúng tôi có == (equal operator) để kiểm tra tính bình đẳng của hai đối tượng. Toán tử == xác nhận xem các giá trị/tham chiếu có bằng nhau cho hai đối tượng nguyên thủy khác nhau hay không. Nhưng điều này không phải lúc nào cũng có thể trả lời chỉ bằng cách kiểm tra với toán tử ==.

Bây giờ câu hỏi là, liệu sự bình đẳng này, which is also a contract, có nên được tiêm qua giao diện hoặc một phần của lớp Object không?

Nếu chúng ta hãy xem, chúng ta không thể chỉ nói một cái gì đó như:

TypeX không đảm bảo hợp đồng bình đẳng.

Nó sẽ trở thành sự hỗn loạn nếu một số loại đối tượng cung cấp sự bình đẳng và một số loại thì không. Điều này có nghĩa là đối tượng của TypeX phải tôn trọng hợp đồng bình đẳng là đúng cho tất cả các loại đối tượng khác. Vì vậy, nó không phải tiêm bình đẳng từ một giao diện, bởi vì bình đẳng nên là một phần của hợp đồng cho bất kỳ đối tượng theo mặc định, nếu không nó sẽ tạo ra sự hỗn loạn.

Vì vậy, chúng tôi cần các đối tượng để đưa ra triển khai equals. Nhưng nó không thể chỉ thực hiện phương thức equals, nó cũng cần triển khai phương thức hashcode.

+2

'=' thực sự là toán tử gán;) –

+0

@DaveNewton cảm ơn bạn. thay đổi cho phù hợp – Kowser

+1

Tôi không hiểu "hỗn loạn" bạn đề cập đến. Tôi thực hiện tất cả các phương pháp này để sử dụng các lớp của tôi trong Bộ và Bản đồ. Nó sẽ đơn giản hơn cho tôi để tránh việc thực hiện mặc định bằng mọi giá, vì vậy tôi sẽ xóa các phương thức này khỏi Object. : D –

1

(Cá nhân, nếu họ ở trong một giao diện, tôi muốn đặt chúng cả ở đó để tránh ít nhất một lớp equals/hashCode những sai lầm.)

Tôi nghĩ rằng bạn muốn một thực hiện trong Object, như một cơ chế rút lui, có nghĩa là mọi thứ sẽ có một sự thực hiện dù sao, giao diện hay không.

Tôi nghi ngờ rất nhiều về lịch sử; lập trình Java ngày nay trông hơi khác một chút so với lập trình Java rồi.

0

Thực hiện chung của nó. Bạn có nghĩa vụ phải ghi đè lên việc thực hiện nếu bạn cần chúng. Nếu không, bạn có triển khai mặc định hợp lý.

Ít nhất phải bằng. Tạo giao diện cho các hoạt động cơ bản có thể sẽ liên quan đến nhiều chi phí.

+0

Điểm của bạn là? – delnan

1

Mhh không chắc chắn nhưng khi Java 1.0 được phát hành generics đã không tồn tại được nêu ra. Chúng được thêm vào trong Java 5.0 vào năm 2004 .. do đó đề xuất của bạn không thể được triển khai cho Java 1.0

+2

Nếu 'TreeSet' có thể yêu cầu các phím để thực hiện' Comparable' nếu không có 'Comparator' được chỉ định, tại sao HashSet không thể yêu cầu' Hashable'? Có nhiều hơn nó so với generics. – meriton

0

Nếu bạn có danh sách các đối tượng và bạn gọi phương thức thì nên làm gì? Tôi nghĩ rằng việc thực hiện mặc định (so sánh tài liệu tham khảo) là một quyết định tốt. Bằng cách này, bạn sẽ không phải tự mình triển khai equalshashcode cho mọi lớp bạn sử dụng trong bộ sưu tập.

1

Ban đầu, trong Java, không có generics. Điều này đã được giải quyết bằng cách cho phép bất kỳ Object trở thành thành viên của bất kỳ bộ sưu tập nào và do đó, cần ObjecthashCodeequals. Bởi bây giờ nó quá cố thủ để thay đổi.

+0

Sự vắng mặt của generics là không thích hợp. Ví dụ, nó không dừng 'TreeSet' từ việc yêu cầu các khóa để thực hiện' Comparable' nếu không có 'Comparator' được chỉ định. – meriton

2

Việc triển khai mặc định trong java.lang.Object có ý nghĩa. Thông thường, nó đủ tốt. Trong các ứng dụng JPA/web, tôi thấy bản thân mình rất hiếm khi ghi đè bằng và hashCode.

Câu hỏi hay hơn có thể là: đối với các đối tượng giá trị bất biến như String, Long, v.v. tại sao bạn không thể ghi đè toán tử == để gọi bằng(), giống như bạn có thể trong C#? Tôi đã nhìn thấy lỗi nhiều hơn vì điều đó hơn tôi có của bằng/hashCode mặc định không làm điều đúng. Ví dụ:

Long x = obj.getId(); 
Long y = obj2.getId(); 
if (x == y) { // oops, probably meant x.equals(y)! } 

Đó là một câu hỏi hợp lý, tuy nhiên, phương pháp mặc định không bị khóa phía sau giao diện gắn thẻ như Object.clone mặc định() mặc định. Có một cài đặt mặc định nhưng bạn phải xác nhận rõ ràng rằng bạn muốn sử dụng nó bằng cách thực hiện Cloneable. Có thể dễ dàng có được một giao diện gắn thẻ tương tự như Sưu tập hoặc Equatable, và sau đó chữ ký cho các phương thức thu thập có thể đã được Equatable thay vì Object.

0

Thực sự, nó chỉ thuận tiện và tốt hơn theo cách này. Hãy suy nghĩ về những gì cần thiết để làm bình đẳng đối tượng nếu bạn không có phương thức .equals:

AreEqual(Object obj1,Object obj2) { 
    if(!obj1 instanceof Equalable) return false; 
    if(!obj2 instanceof Equalable) return false; 
    return ((Equalable)(obj1).equals((Equalable)obj2); 
} 

Điều này đúng ngay cả đối với mã băm. Đôi khi bình đẳng tham chiếu là đủ. Nếu bạn đã thực hiện HashSet chỉ chấp nhận các đối tượng thực hiện Hashable, thì bạn phải rõ ràng làm cho các lớp của bạn Hashable, mặc dù bạn chỉ muốn tham chiếu bình đẳng. Và bạn đã giảm tính phổ quát của một cấu trúc dữ liệu tuyệt vời khác. Tốt hơn là để Object có chức năng mặc định (và đôi khi đủ) .equals và .hashCode và gây ra một vài vấn đề cho người mới, hơn là làm cho người dùng thường xuyên truy cập ngôn ngữ qua nhiều băng màu đỏ hơn.

0

Bất kỳ đối tượng nào, bất kể loại nào, có thể trả lời một cách hợp lý cho dù đối tượng đó có tương đương với bất kỳ đối tượng nào khác, ngay cả khi loại đối tượng khác không phải là đối tượng. Nếu nó không bao giờ nghe về kiểu của đối tượng khác, thực tế đó là đủ để nó báo cáo rằng nó không tương đương với đối tượng thứ hai.

Các vấn đề liên quan