Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/383.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/oop/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 为什么在Object中定义equals和hashCode?_Java_Oop_Equals_Hashcode - Fatal编程技术网

Java 为什么在Object中定义equals和hashCode?

Java 为什么在Object中定义equals和hashCode?,java,oop,equals,hashcode,Java,Oop,Equals,Hashcode,决定在java.lang.Object中包含这些方法的原因是什么?相等和散列对于许多类来说没有意义 制作两个接口更符合逻辑: interface Equalable { boolean equals(Equalable other); } interface Hashable extends Equalable { int hashCode(); } 例如,HashSet定义可能如下所示 class HashSet<T extends Hashable> ...

决定在java.lang.Object中包含这些方法的原因是什么?相等和散列对于许多类来说没有意义

制作两个接口更符合逻辑:

interface Equalable {
    boolean equals(Equalable other);
}

interface Hashable extends Equalable {
    int hashCode();
}
例如,HashSet定义可能如下所示

class HashSet<T extends Hashable> ...
类哈希集。。。
它可以防止一个常见的初学者错误——在不实现equals/hashCode的情况下使用一组项。

(就个人而言,如果它们在一个接口中,我会将它们都放在那里,以避免至少一类
equals
/
hashCode
错误。)

我认为您需要对象中的一个实现,作为一种回退机制,这意味着任何东西都会有一个实现,不管接口与否


我怀疑其中很多是历史性的;今天的Java编程看起来与当时的Java编程有很大不同。

这是一个通用的实现。如果需要,应该重写实现。否则,您将有一个合理的默认实现


至少平等是必须的。为基本操作创建接口可能会涉及大量开销。

Mhh不确定,但Java 1.0发布时,泛型还不存在。它们是在2004年在Java 5.0中添加的。。因此,您的建议无法在Java 1.0上实现,如果您有一个对象列表,并且调用
contains
方法,那么
Java
应该做什么?我认为默认实现(比较引用)是一个不错的决定。这样,您就不必为集合中使用的每个类实现自己的
equals
hashcode

最初,在Java中没有泛型。这是通过允许任何
对象
成为任何集合的成员来解决的,因此任何
对象
都需要
hashCode
等于
。现在它已经根深蒂固,无法改变。

java.lang.Object中的默认实现是有意义的。很多时候,这已经足够好了。在JPA/web应用程序中,我发现自己很少重写equals和hashCode

更好的问题可能是:对于字符串、Long等不可变值对象,为什么不能像在C#中那样重写==运算符来调用equals()?因此,我看到的错误比默认的equals/hashCode没有做正确的事情多得多。比如说,

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

不过,这是一个公平的问题,为什么默认方法没有像默认的Object.clone()那样锁定在标记接口后面。有一个默认的实现,但您必须明确承认您希望通过实现Cloneable来使用它。也可以很容易地有一个类似的标记接口,如Collectible或Equatable,然后collections方法的签名可以是Equatable而不是Object。

当我们实现一个接口时,我们注入(或接受)接口定义的契约

Equalable
Hashable
是两种不同的合同。但如果我们仔细观察,就会发现它们彼此依赖,这意味着它们是
单个接口的一部分,类似于
equalableandhable

现在一个明显的问题是,它们是否应该成为这个新的
equalableandhable
接口或
对象的一部分

让我们看看。我们有
==
(相等运算符)来检查两个对象的相等性<代码>=
运算符确认两个不同的原语/对象的值/引用是否相等。但是,仅仅通过使用
=
操作符进行检查并不总是能够回答这个问题

现在的问题是,是否应该通过接口或对象类的一部分来注入这个等式,它也是一个契约

如果我们看一看,我们不能只是说:

TypeX
不保证合同的平等性

如果某些对象类型提供相等,而某些对象类型不提供相等,则会变得混乱。这意味着
TypeX
的对象必须遵守平等契约,这同样适用于所有其他对象类型。因此,它不能从接口注入平等,因为平等在默认情况下应该是任何对象的契约的一部分,否则它将造成混乱


所以我们需要对象来实现
equals
。但是它不能只实现
equals
方法,它还需要实现
hashcode
方法。

实际上,这只是为了方便,这样更好。好吧,想想如果没有.equals方法,要实现对象相等需要什么:

AreEqual(Object obj1,Object obj2) {
  if(!obj1 instanceof Equalable) return false;
  if(!obj2 instanceof Equalable) return false;
  return ((Equalable)(obj1).equals((Equalable)obj2);
}
即使对于哈希代码也是如此。有时引用相等就足够了。如果您使HashSet只接受实现Hashable的对象,那么您必须显式地使类可哈希,即使您只希望引用相等。你已经减少了一个伟大的数据结构的通用性


最好让对象有一个默认值(有时足够了).equals和.hashCode函数,并给新手带来一些问题,而不是让这种语言的频繁用户费力地通过更多的繁文缛节。

任何对象,无论其类型如何,都可以明智地回答它是否与任何其他对象等效,即使另一个对象的类型是它从未听说过的类型。如果它从未听说过另一个对象的类型,仅此事实就足以报告它与后一个对象不同。

在@Kowser关于“混乱”的回答中添加注释:

equals的隐式逻辑要求它必须满足以下特征:

  • 它是自反的:对于任何非空参考值x,x.equals(x)应该返回true
  • 它是对称的:对于任何非空的引用值x和y,当且仅当y.equals(x)返回true时,x.equals(y)才应返回true
  • 它是可传递的:对于任何非null ref