接口中的 toString()、equals() 和 hashCode()

发布于 2024-08-10 21:02:22 字数 292 浏览 9 评论 0原文

所以,我有一个带有一堆需要实现的方法的接口,方法名称无关紧要。

实现此接口的对象通常被放入集合中,并且还具有我希望它们使用的特殊 toString() 格式。

因此,我认为将 hashCode()、equals() 和 toString() 放入接口中会很方便,以确保我记得重写这些的默认方法。但是,当我将这些方法添加到接口时,如果我没有实现这三个方法,IDE/编译器不会抱怨,即使我明确地将它们放入接口中。

为什么这不会对我强制执行?如果我不实现任何其他方法,它会抱怨,但它不会强制执行这三种方法。什么给?有什么线索吗?

So, I have an interface with a bunch of methods that need to be implemented, the method names are irrelevant.

The objects that implement this interface are often put into collections, and also have a special toString() format that I want them to use.

So, I thought it would be convenient to put hashCode(), equals(), and toString() into the interface, to make sure that I remember to override the default method for these. But when I added these methods to the interface, the IDE/Compiler doesn't complain if I don't have those three methods implemented, even though I explicitly put them in the interface.

Why won't this get enforced for me? It complains if I don't implement any of the other methods, but it doesn't enforce those three. What gives? Any clues?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(12

少女情怀诗 2024-08-17 21:02:22

听起来您想强制您的类覆盖这些方法的默认实现。如果是这样,执行此操作的方法是声明一个抽象超类,其中的方法声明为抽象。例如:

public abstract class MyBaseClass implements ... /* existing interface(s) */ {

    public abstract boolean equals(Object other);

    public abstract int hashCode();

    public abstract String toString();
}

然后更改当前的类来扩展该类。

这种方法确实有效,但并不是理想的解决方案。

  • 这对于现有的类层次结构来说可能会出现问题。

  • 强制实现现有接口的类扩展特定的抽象类是一个坏主意。例如,您可以更改方法签名中的参数以使用抽象类而不是现有接口。但最终的结果是代码不太灵活。 (无论如何,人们都可以找到方法来颠覆这一点;例如,通过添加自己的抽象子类,通过 super.(...) 调用“实现”方法!)

  • 强加特定的类层次结构/实现模式是短视的。您无法预测未来的某些需求变化是否意味着您的限制会带来困难。 (这就是为什么人们建议针对接口而不是特定类进行编程。)


回到关于为什么接口不强制类重新声明这些方法的实际问题:

为什么这不会对我强制执行?如果我不实现任何其他方法,它会抱怨,但它不会强制执行这三种方法。什么给?有什么线索吗?

接口施加了这样的约束:实现它的具体类具有每个方法的实现。但是,它并不要求类本身提供这些方法。方法实现可以从超类继承。在这种情况下,这就是正在发生的事情。从java.lang.Object继承的方法满足约束。

JLS 8.1.5 声明如下:

“除非所声明的类是抽象的,否则每个直接超级接口的所有抽象成员方法都必须通过此类中的声明或通过继承的现有方法声明来实现(第 8.4.8.1 节)来自直接超类或直接超接口,因为非抽象类不允许具有抽象方法(第 8.1.1.1 节)。”

It sounds like you want to force your classes to override the default implementations of those methods. If so, the way to do this is to declare an abstract superclass that has the methods declared as abstract. For example:

public abstract class MyBaseClass implements ... /* existing interface(s) */ {

    public abstract boolean equals(Object other);

    public abstract int hashCode();

    public abstract String toString();
}

Then change your current classes to extend this class.

This approach kind of works, but it is not an ideal solution.

  • It can be problematic for an existing class hierarchy.

  • It is a bad idea to force classes that implement your existing interface to extend a specific abstract class. For example, you can change parameters in method signatures to use the abstract class rather than the existing interface(s). But the end result is less flexible code. (And people can find ways to subvert this anyway; e.g. by adding their own abstract subclass that "implements" the methods with a super.<method>(...) call!)

  • Imposing a particular class hierarchy / implementation pattern is short sighted. You cannot predict whether some future requirement change will mean that your restrictions cause difficulties. (This is why people recommend programming against interfaces rather than specific classes.)


Back to your actual question about why your interface doesn't force a class to redeclare those methods:

Why won't this get enforced for me? It complains if I don't implement any of the other methods, but it doesn't enforce those three. What gives? Any clues?

An interface imposes the constraint that a concrete class implementing it has an implementation for each of the methods. However, it doesn't require that the class itself provides those methods. The method implementations can be inherited from a superclass. And in this case, that is what is happening. The methods inherited from java.lang.Object saftisfy the constraint.

JLS 8.1.5 states the following:

"Unless the class being declared is abstract, all the abstract member methods of each direct superinterface must be implemented (§8.4.8.1) either by a declaration in this class or by an existing method declaration inherited from the direct superclass or a direct superinterface, because a class that is not abstract is not permitted to have abstract methods (§8.1.1.1)."

甜嗑 2024-08-17 21:02:22

Java 中的所有对象都继承自 java.lang.ObjectObject 提供这些方法的默认实现。

如果您的接口包含其他方法,如果您没有通过提供这些方法的实现来完全实现该接口,Java 会发出警告。但是对于 equals()hashCode()toString() (以及您没有提到的其他一些)实施已经存在。

您可能能够完成您想要的任务的一种方法是在界面中提供不同的方法,例如 toPrettyString() 或类似的方法。然后您可以调用该方法而不是默认的 toString() 方法。

All objects in Java inherit from java.lang.Object and Object provides default implementations of those methods.

If your interface contains other methods, Java will complain if you don't implement the interface fully by providing an implementation of those methods. But in the case of equals(), hashCode() and toString() (as well as a few others that you didn't mention) the implementation already exists.

One way you might be able to accomplish what you want is by providing a different method in the interface, say, toPrettyString() or something like that. Then you can call that method instead of the default toString() method.

铁轨上的流浪者 2024-08-17 21:02:22

所有这 3 个方法均由 java.lang.Object 定义。 lang.Object 由所有其他类(隐式)扩展;因此,这些方法的默认实现是存在的,编译器没有什么可抱怨的。

All 3 of those methods are defined by java.lang.Object which is (implicitly) extended by all other classes; therefore default implementations for those methods exist and compiler has nothing to complain about.

醉生梦死 2024-08-17 21:02:22

任何实现您的接口的类也会扩展 Object。 Object 定义了 hashCode、equals 和 toString,并且具有所有三个的默认实现。

你想要实现的目标是好的,但不切实际。

Any class that implements your interface also extends Object. Object defines hashCode, equals, and toString and has default implementations of all three.

What you are trying to achieve is good, but not practicable.

情绪失控 2024-08-17 21:02:22

如果要强制重写 equals() 和 hashCode(),请从抽象超类扩展,该超类将这些方法定义为抽象方法。

If you want to force overriding of equals() and hashCode(), extend from an abstract superclass, which defines these methods as abstract.

我是男神闪亮亮 2024-08-17 21:02:22

这些方法都有一个来自 Object 的实现。

There's an implementation for those methods coming all the way from Object.

云醉月微眠 2024-08-17 21:02:22

您的对象已经包含这三个方法的实现,因为每个对象都从 Object 继承这些方法,除非它们被重写。

Your object already contains implementations of those three methods, because every object inherits those methods from Object, unless they are overridden.

笛声青案梦长安 2024-08-17 21:02:22

其他人已经充分回答了您的实际问题。至于针对您的特定问题的解决方案,您可以考虑创建自己的方法(可能是 getStringRepresentation、getCustomHashcode 和 equalsObject),并让您的对象扩展一个基类,该基类的 equals、toString 和 hashCode 方法调用这些方法。

不过,这可能会违背使用接口的初衷。这就是一些人建议 equals、toString 和 hashCode 一开始就不应该包含在 Object 类中的原因之一。

Other people have answered your actual question sufficiently. As far as a solution for your particular problem, you might consider creating your own methods (maybe getStringRepresentation, getCustomHashcode, and equalsObject), and have your objects extend a base class whose equals, toString, and hashCode methods call these methods.

This might defeat the purpose of using an interface in the first place, though. This is one of the reasons that some people have suggested that equals, toString, and hashCode should never have been included on the Object class in the first place.

凯凯我们等你回来 2024-08-17 21:02:22

Java 只关心方法是在某个地方定义的。如果已经定义了第一次从接口继承的新类中的方法,该接口不会强制您重新定义这些方法。由于 java.lang.Object 已经实现了这些方法,因此您的新对象即使不自行重写这三个方法,也符合该接口。

Java only cares that the methods are defined somewhere. The interface doesn't force you to redefine the methods in new classes that inherit from the interface for the first time if they're already defined. Since java.lang.Object already implements these methods, your new objects conform to the interface even if they don't override these three methods on their own.

孤独陪着我 2024-08-17 21:02:22

Adam 向您解释了为什么您无法尝试强制使用 equals、hashCode 和 toString。我将采用以下实现,该实现涉及 Adam 和 Stephan 提供的解决方案:

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();
    }
}

现在,任何要求自身明确不同并表示为 String 的类都可以扩展 DistinctStringableObject,这将强制实现 checkEquals、hashCode 和 toString。

具体类示例:

public abstract class MyDistinctStringableObject extends DistinctStringableObject {

    @Override
    public final boolean checkEquals(Object other) {
        ...
    }

    @Override
    public final int hash() {
        ...
    }

    @Override
    public final String asString() {
        ...
    }
}

Adam gives you the reason why you cannot get away with trying to force equals, hashCode and toString. I would go for the following implementation which touches the solution provided by Adam and Stephan:

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();
    }
}

Now, any class which requires itself to definitely distinct and represented as a String can extend the DistinctStringableObject which will force implementation of checkEquals, hashCode and toString.

Sample concrete class:

public abstract class MyDistinctStringableObject extends DistinctStringableObject {

    @Override
    public final boolean checkEquals(Object other) {
        ...
    }

    @Override
    public final int hash() {
        ...
    }

    @Override
    public final String asString() {
        ...
    }
}
摘星┃星的人 2024-08-17 21:02:22

如果您有孙子,抽象类将无法工作,因为它的父亲已经重写了 equals 和 hashCode 方法,然后您的问题又会出现。

尝试使用注释和 APT (http://docs.oracle .com/javase/1.5.0/docs/guide/apt/GettingStarted.html)来完成它。

Abstract classes won't work if you have a grandchild since its father already overrided both equals and hashCode methods and then you have your problem all over again.

Try using annotatins and APT (http://docs.oracle.com/javase/1.5.0/docs/guide/apt/GettingStarted.html) to get it done.

忘年祭陌 2024-08-17 21:02:22

好吧,如果您声明了一个接口,其中默认情况下所有方法都是抽象的,并且您确实需要提供功能,但是当您在子类中实现它时,您就提供了实现权。
正如你所看到的,每个类都是一个超类的子类(简单地说,Object 是所有类的超类)
因此,如果您有一个实现接口的类,您需要提供方法的实现。但这里需要记住一件事。

不管怎样,如果您没有在接口中声明这些方法,那么首先实现该接口的子类仍然具有这种行为。

所以如果不声明它,它仍然会存在,另一件事是,由于这些方法和 Object 类的其他方法对于类的所有对象都存在,所以不需要实现。

well if u have declared an interface in which by default all the methods are abstract and u do need to provide the functionality but when u implement it in the subclass, then u provide the implementation right.
as you can see that every class is the subclass of one superclass(put simply Object is superclass of all the classes)
so if u have a class implementing an interface, u need to provide implementation for the methods. but a thing needs to be remembered here that.

irrespective of, if u didn't declare these methods in the interface, you still had this behavior for the subclass that implemented the interface in the first place.

so if don't declare it, it still will be present and another thing is that since these methods and other methods of Object class are present for all the objects of classes, so there is no need for implementation.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文