Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/397.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.equals()实例?为什么不把超类称为equals而不是final呢?_Java_Equals_Instanceof - Fatal编程技术网

子类的Java.equals()实例?为什么不把超类称为equals而不是final呢?

子类的Java.equals()实例?为什么不把超类称为equals而不是final呢?,java,equals,instanceof,Java,Equals,Instanceof,它在对象的.equals(Object)javadoc中说明: 它是对称的:对于任何非空参考值x和y, x、 当且仅当y.equals(x)返回时,equals(y)应返回true 对 在示例代码中,几乎所有地方都可以看到重写的.equals(Object)方法,该方法使用instanceof作为第一个测试之一,例如: } 现在,使用类SpecialPerson扩展Person中的等于: if (!(obj instanceof SpecialPerson))

它在对象的
.equals(Object)
javadoc中说明:

它是对称的:对于任何非空参考值x和y, x、 当且仅当y.equals(x)返回时,equals(y)应返回true 对

在示例代码中,几乎所有地方都可以看到重写的
.equals(Object)
方法,该方法使用
instanceof
作为第一个测试之一,例如:

}

现在,使用
类SpecialPerson扩展Person
中的
等于:

        if (!(obj instanceof SpecialPerson))
            return false;
我们不能保证
.equals()
是对称的。 这里已经讨论过,例如:

也许我应该在SpecialPerson的equals直接呼叫super的开头加上

    public boolean equals(Object obj) {
        if( !obj instanceof SpecialPerson )
            return super.equals(obj);
        ... 
        /* more equality tests here */
    }

你试图解决这个问题是不对的。假设您有两个子类
SpecialPerson
BizarrePerson
。通过这个实现,
BizarrePerson
实例可以等于
SpecialPerson
实例。你通常不希望这样。

你在这里遗漏了一些东西。我将努力强调这一点:

假设您有
Person-Person=new-Person()
Person-personSpecial=new-SpecialPerson()
,那么我肯定您不希望这两个对象相等。因此,它确实按要求工作,相等的值必须返回false


此外,对称性指定两个类中的
equals()
方法必须同时遵守它。如果一个equals返回true,另一个equals返回false,那么我会说缺陷在于equals重写。

许多示例使用
instanceof
有两个原因:A)它将null检查和类型检查折叠为一个或b)该示例用于Hibernate或其他代码重写框架

“正确的”(根据JavaDoc)解决方案是使用
this.getClass()==obj.getClass()
。这适用于Java,因为类是单例的,VM保证了这一点。如果你是偏执狂,你可以使用
this.getClass().equals(obj.getClass())
,但两者实际上是等价的

这在大多数情况下都有效。但有时,Java框架需要用字节码做“聪明”的事情。这通常意味着它们会自动创建子类型。由于子类型应被视为等于原始类型,
equals()
必须以“错误”的方式实现,但这并不重要,因为在运行时,子类型都将遵循某些模式。例如,在调用setter之前,他们将执行其他操作。这对“平等性”没有影响


正如您所注意到的,当您同时使用这两种情况时,情况开始变得糟糕:您确实扩展了基本类型,并将其与自动子类型生成相混合。如果这样做,必须确保从不使用非叶类型。

不要使用
instanceof
。改用
this.getClass()==obj.getClass()
。那么你要检查的正是这门课

使用
equals
时,应始终使用
hashCode
并覆盖它

Person的hashCode方法可能如下所示:

@Override
public int hashCode()
{
    final int prime = 31;
    int result = 1;
    result = prime * result + age;
    result = prime * result + ((name == null) ? 0 : name.hashCode());
    return result;
}
在equals方法中使用它:

if (this.hashCode() != obj.hashCode())
{
    return false;
}

一个类型不应该把它自己等同于任何其他类型的对象——甚至是一个子类型——除非两个对象都从一个公共类派生,该类的契约指定了不同类型的子代应该如何检查相等性。


例如,抽象类
StringyThing
可以封装字符串,并提供转换为字符串或提取子字符串等方法,但不会对备份格式提出任何要求。例如,
StringyThing
的一个可能的子类型可能包含一个
StringyThing
数组,并封装所有这些字符串的串联值。如果转换为字符串将产生相同的结果,
StringyThing
的两个实例将被定义为相等的,并且两个本来无法区分的
StringyThing
实例之间的比较可能不得不依赖于此,但是
StringyThing
-派生类型可以包括优化各种情况的代码。例如,如果一个
StringyThing
表示“
M
字符
ch
的重复”,另一个表示“
N
字符串St的重复”,并且后一种类型知道第一个,它可以检查
St
是否只包含
M/N
字符的重复
ch
。这样的检查将指示字符串是否相等,而不必“展开”其中任何一个字符串。

有效的java中也讨论了类似的问题。您可以读到这一点。要添加到Manoose注释有效的Java SAI:“避免问题的最简单方法是不重写equals方法,在这种情况下,每个实例只与自身相等。如果应用以下任何条件,这是正确的做法:[……]一个超类已经覆盖了equals,并且从超类继承的行为适合于这个类。“可能的重复性——在许多情况下,将两个不同子类的实例视为相等是有意义的。以
列表
为例。
ArrayList
是并且应该等于包含相同元素的
LinkedList
。但是您可能不想在子类中重写equals,这就是这个问题的全部内容。你能引用文档中与你的第二段相符的部分吗?@arshajii:这是classloader合同的一部分。标准类加载器将始终为相同的类名返回相同的引用。当然,对于脚本类加载器来说,赌注是输的。哦,我的意思是“正确的解决方案是使用…”。你是说比较
equals()
i中的
getClass()
s更好吗
@Override
public int hashCode()
{
    final int prime = 31;
    int result = 1;
    result = prime * result + age;
    result = prime * result + ((name == null) ? 0 : name.hashCode());
    return result;
}
if (this.hashCode() != obj.hashCode())
{
    return false;
}