Java 接口中的toString()、equals()和hashCode()
因此,我有一个接口,其中包含一系列需要实现的方法,这些方法的名称是不相关的 实现此接口的对象通常被放入集合中,并且我希望它们使用一种特殊的toString()格式 因此,我认为将hashCode()、equals()和toString()放入接口中会很方便,以确保我记得覆盖这些函数的默认方法。但是当我将这些方法添加到接口时,如果我没有实现这三个方法,IDE/编译器不会抱怨,即使我显式地将它们放在接口中Java 接口中的toString()、equals()和hashCode(),java,interface,equals,hashcode,tostring,Java,Interface,Equals,Hashcode,Tostring,因此,我有一个接口,其中包含一系列需要实现的方法,这些方法的名称是不相关的 实现此接口的对象通常被放入集合中,并且我希望它们使用一种特殊的toString()格式 因此,我认为将hashCode()、equals()和toString()放入接口中会很方便,以确保我记得覆盖这些函数的默认方法。但是当我将这些方法添加到接口时,如果我没有实现这三个方法,IDE/编译器不会抱怨,即使我显式地将它们放在接口中 为什么我不能强制执行?如果我没有实现任何其他方法,它会抱怨,但它没有强制执行这三种方法。有什么
为什么我不能强制执行?如果我没有实现任何其他方法,它会抱怨,但它没有强制执行这三种方法。有什么好处?有什么线索吗?所有这三个方法都是由所有其他类(隐式)扩展的方法定义的;因此,这些方法的默认实现是存在的,编译器没有什么可抱怨的。Java中的所有对象都继承自
Java.lang.Object
,并提供这些方法的默认实现
如果您的接口包含其他方法,那么如果您没有通过提供这些方法的实现来完全实现接口,Java会抱怨。但是在equals()
、hashCode()
和toString()
(以及您没有提到的其他一些)的情况下,实现已经存在
实现所需功能的一种方法是在接口中提供不同的方法,例如,
toPrettyString()
或类似的方法。然后您可以调用该方法,而不是默认的toString()
方法。这些方法都是从对象来实现的。实现接口的任何类都会扩展对象。对象定义hashCode、equals和toString,并具有这三个的默认实现
您试图实现的是好的,但不可行。您的对象已经包含了这三种方法的实现,因为每个对象都从对象继承这些方法,除非它们被重写。Java只关心这些方法是在某处定义的。接口不会强制您在新类中重新定义方法,这些新类第一次从接口继承,如果它们已经定义。由于java.lang.Object
已经实现了这些方法,因此您的新对象符合接口,即使它们没有自己重写这三个方法。其他人已经充分回答了您的实际问题。至于解决特定问题的方法,您可以考虑创建自己的方法(可能是GestStRePress、GETCuthHashCad和ErraseObjor),并使对象扩展一个基类,其相等、ToShand和Hash码方法调用这些方法。
不过,这可能会首先破坏使用接口的目的。这就是为什么有些人认为equals、toString和hashCode从一开始就不应该包含在对象类中的原因之一。听起来像是要强制类重写这些方法的默认实现。如果是这样,那么方法就是声明一个抽象超类,该类的方法声明为抽象。例如:
public abstract class MyBaseClass implements ... /* existing interface(s) */ {
public abstract boolean equals(Object other);
public abstract int hashCode();
public abstract String toString();
}
然后将当前类更改为extend
this class
这种方法是可行的,但不是理想的解决方案
- 对于现有的类层次结构来说,这可能会有问题
- 强制实现现有接口的类扩展特定的抽象类是个坏主意。例如,您可以更改方法签名中的参数以使用抽象类而不是现有接口。但最终的结果是代码的灵活性降低了。(人们无论如何都可以找到颠覆这一点的方法;例如,通过添加自己的抽象子类,用
super.(……
call!)来“实现”这些方法。)
- 强加特定的类层次结构/实现模式是短视的。您无法预测未来的需求变化是否意味着您的限制会导致困难。(这就是为什么人们建议针对接口而不是特定类进行编程。)
回到您的实际问题,即为什么您的接口不强制类重新声明这些方法:
为什么我不能强制执行?如果我没有实现任何其他方法,它会抱怨,但它没有强制执行这三种方法。有什么好处?有什么线索吗
接口施加了一个约束,即实现它的具体类对每个方法都有一个实现。但是,它并不要求类本身提供这些方法。方法实现可以从超类继承。在这种情况下,这就是正在发生的事情。继承自java.lang.Object
的方法可以满足约束
声明如下:
“除非所声明的类是抽象的,否则必须实现每个直接超级接口的所有抽象成员方法(§8.4.8.1)通过此类中的声明或从直接超类或直接超接口继承的现有方法声明,因为非抽象类不允许有抽象方法(§8.1.1.1)。”
如果要强制重写equals()和hashCode(),请从抽象超类进行扩展,抽象超类将这些方法定义为抽象。如果您声明了一个接口,其中默认情况下所有方法都是抽象的,并且您确实需要提供功能,但是当您在子类中实现它时,然后你提供了实现权。
正如您所看到的,每个类都是一个超类的子类(简单地说,对象是sup)
public interface Distinct {
boolean checkEquals(Object other);
int hash();
}
public interface Stringable {
String asString();
}
public abstract class DistinctStringableObject {
@Override
public final boolean equals(Object other) {
return checkEquals();
}
@Override
public final int hashCode() {
return hash();
}
@Override
public final String toString() {
return asString();
}
}
public abstract class MyDistinctStringableObject extends DistinctStringableObject {
@Override
public final boolean checkEquals(Object other) {
...
}
@Override
public final int hash() {
...
}
@Override
public final String asString() {
...
}
}