强制类重写 .equals 方法

发布于 2024-08-08 21:19:21 字数 256 浏览 2 评论 0原文

我有一群实现通用接口的类:Command。

这群类转到 Map 。

为了让 Map 正常工作,我需要每个实现 Command 的类重写 Object.equals(Object other) 方法。

没关系。

但我想强制平等凌驾于一切之上。 =>当执行命令的内容不覆盖 equals 时,会出现编译错误。

这可能吗?

编辑:顺便说一句,我还需要强制覆盖哈希码......

I have a bunch of class who implement a common interface : Command.

And this bunch of class goes to a Map.

To get the Map working correctly, I need to each class who implements Command to override the Object.equals(Object other) method.

it's fine.

But i whould like to force the overriding of equals. => Have a compilation error when something who implement command dont override equals.

It's that possible ?

Edit : BTW , i will also need to forcing the override of hashcode...

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

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

发布评论

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

评论(12

〆凄凉。 2024-08-15 21:19:21

不,你不能。但是,您可以做的是使用抽象基类而不是接口,并使 equals() 抽象:

abstract class Command {
   // put other methods from Command interface here

   public abstract boolean equals(Object other);
   public abstract int hashCode();
}

Command 的子类必须然后提供自己的 equals 和 hashCode 方法。

强制 API 用户扩展基类通常是不好的做法,但在这种情况下可能是合理的。另外,如果您将 Command 设为抽象基类而不是接口,而不是在 Command 接口的基础上引入人工基类,那么您的 API 就不存在风险用户弄错了。

No, you can't. What you can do, however, is use an abstract base class instead of an interface, and make equals() abstract:

abstract class Command {
   // put other methods from Command interface here

   public abstract boolean equals(Object other);
   public abstract int hashCode();
}

Subclasses of Command must then provide their own equals and hashCode methods.

It's generally bad practice to force API users to extend a base class but it may be justified in this case. Also, if you make Command an abstract base class instead of an interface, rather than introducing an artificial base class in addition to the Command interface, then there's no risk of your API users getting it wrong.

欲拥i 2024-08-15 21:19:21

您可以从抽象 XObject 而不是 java.lang.Object 扩展对象吗?

public abstract class XObject
 extends Object
{
@Override
public abstract boolean equals(Object o);
}

Can you extend your objects from an abstract XObject rather than java.lang.Object ?

public abstract class XObject
 extends Object
{
@Override
public abstract boolean equals(Object o);
}
要走干脆点 2024-08-15 21:19:21

如果您有孙子,抽象类将无法工作,因为它的父亲已经重写了 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-15 21:19:21

仅当 Command 是接口或抽象类时才可能实现,其中 equals(..) 是声明为抽象的方法。

问题在于,作为所有对象的超类的 Object 已经定义了此方法。

如果您希望表明这是一个问题(在运行时),您可以抛出异常,以强制 API 的用户覆盖它。但至少据我所知,在编译时这是不可能的。

尝试通过使用特定于 API 的方法(例如 CommandEquals)来解决这个问题。另一个选项是(如上所述)扩展另一个定义 Equals 抽象方法的类。

This would only be possible if Command was an interface, or an abstract class, where equals(..) is a method declared as abstract.

The problem is that Object, which is the superclass of all objects, already defines this method.

If you wish to indicate that this is a problem (at run-time), you could throw an exception, to force users of your API to override it. But it is not possible at compile time, at least to my knowledge.

Try to work around it, by having an API-specific method, e.g. CommandEquals. The other option is (as mentioned) extend another class which defines an Equals abstract method.

那些过往 2024-08-15 21:19:21

您可以在interface Command中创建boolean myEquals(),并像这样创建适配器:

class MyAdapter{
  Command c;
  boolean equals(Object x) {
    return c.myEquals((Command)x);
  }
}

然后您只需使用map.put(key, new MyAdapter(command)) 而不是 map.put(key, command)

You can create boolean myEquals() in interface Command, and create Adapter like this:

class MyAdapter{
  Command c;
  boolean equals(Object x) {
    return c.myEquals((Command)x);
  }
}

Then you just use map.put(key, new MyAdapter(command)) instead of map.put(key, command)

烧了回忆取暖 2024-08-15 21:19:21

如果您想要运行时检查,您可以执行以下操作:

    interface Foo{

}
class A implements Foo {

}
class B implements Foo {
    @Override
    public boolean equals(Object obj) {
        return super.equals(obj);
    }
}

public static void main(String[] args) {
    Class<A> clazzA = A.class;
    Class<B> clazzB = B.class;

    Class<Object> objectClass = Object.class;
    try {
        Method methodFromObject = objectClass.getMethod("equals",Object.class);
        Method methodFromA = clazzA.getMethod("equals",Object.class);
        Method methodFromB = clazzB.getMethod("equals",Object.class);
        System.out.println("Object == A" + methodFromObject.equals(methodFromA));
        System.out.println("Object == B" + methodFromObject.equals(methodFromB));
    } catch (SecurityException e) {
        e.printStackTrace();
    } catch (NoSuchMethodException e) {
        e.printStackTrace();
    }
}

将为第一个打印 true,为第二个打印 false。
如果您希望编译时看起来唯一的选择是创建注释并使用注释处理工具来检查所有带注释的类是否覆盖 equals。

Well if you want a runtime check you can do something like:

    interface Foo{

}
class A implements Foo {

}
class B implements Foo {
    @Override
    public boolean equals(Object obj) {
        return super.equals(obj);
    }
}

public static void main(String[] args) {
    Class<A> clazzA = A.class;
    Class<B> clazzB = B.class;

    Class<Object> objectClass = Object.class;
    try {
        Method methodFromObject = objectClass.getMethod("equals",Object.class);
        Method methodFromA = clazzA.getMethod("equals",Object.class);
        Method methodFromB = clazzB.getMethod("equals",Object.class);
        System.out.println("Object == A" + methodFromObject.equals(methodFromA));
        System.out.println("Object == B" + methodFromObject.equals(methodFromB));
    } catch (SecurityException e) {
        e.printStackTrace();
    } catch (NoSuchMethodException e) {
        e.printStackTrace();
    }
}

Will print true for the first one and false for the second.
If you want it compile time looks like the only option is to create an annotation and use annotation processing tool to check that all annotated classes overrides equals.

淡笑忘祈一世凡恋 2024-08-15 21:19:21
interface A{
    public boolean equal2(Object obj);
}

abstract class B implements A {

    @Override
    public boolean equals(Object obj) {
        return equal2(obj);
    }

}


class C extends B {

    public boolean equal2(Object obj) {
        throw new UnsupportedOperationException("Not supported yet.");
    }
}
interface A{
    public boolean equal2(Object obj);
}

abstract class B implements A {

    @Override
    public boolean equals(Object obj) {
        return equal2(obj);
    }

}


class C extends B {

    public boolean equal2(Object obj) {
        throw new UnsupportedOperationException("Not supported yet.");
    }
}
余生一个溪 2024-08-15 21:19:21

由于 equals() 是从 Object 继承的,我怀疑你不能真正强制这样做,因为对于每个类型都有一个自动继承的实现equals() 可用。

Since equals() is inherited from Object I doubt you can't really force that, since for every type there is an automatic inherited implementation of equals() available.

不弃不离 2024-08-15 21:19:21

我认为不可能强制覆盖 equals,因为它来自 Object 类。

在相关说明中,请注意,当您重写 equals 时,您需要重写 Object 类中的“hashCode”方法。如果您打算使用类的实例作为 Map 的键,这一点就变得特别重要。检查这篇文章:
http://www.artima.com/lejava/articles/equality.html
它提供了一些关于如何以正确的方式覆盖 equals 的提示

I don't think it is possible to force overriding of equals as it comes from the Object class.

On a related note, note that you need to override 'hashCode' method from the Object class when ever you override equals. This becomes espeically important if you are going to use instances of your classes as keys of a Map. Check this article :
http://www.artima.com/lejava/articles/equality.html
which provides some hints about how to override equals in a correct manner

风月客 2024-08-15 21:19:21

正如其他答案已经解释的那样,不,你不能强迫你想要做的事情。

可能“足够”工作的一件事是定义第二个接口,将其称为 MappableCommand。

public interface MappableCommand 
{

}

在该接口的文档中指出,如果类设计者考虑了您所说的要求,则类应该仅实现此(空)接口。

然后,您可以将地图的 Value 类型设置为 MappableCommand,并且只有 MappableCommands 才能添加到地图中。

这类似于为什么需要为可以通过 Java 的默认序列化机制序列化的类实现(空白)接口 Serialized 的逻辑。

如果这不起作用,那么您可能不得不抛出运行时错误;

假编辑:

如果您想让这个要求更加明显,您可以这样定义新界面

public interface MappableCommand 
{

    public void iOverrodeTheEqualsMethod();

    public void seriouslyIPromiseThatIOverrodeIt();

}

As the other answers have already explained, no you cannot force the kind of thing that you are trying to.

One thing that might work 'enough' is to define a second interface, call this one MappableCommand.

public interface MappableCommand 
{

}

In your documentation for this interface indicate that a class should only implement this (empty) interface if the class designer has considered the requirements you stated.

Then you can set the Value type of your map to MappableCommand, and only MappableCommands will be able to be added to the map.

This is similar to the logic behind why one needs to implement the (blank) interface Serializable for classes that can be serialized by Java's default serialization mechanisms.

If this doesn't work, then you may have to settle for throwing a run time error;

Fake Edit:

If you wanted to make this requirement more obvious you could define the new interface this way

public interface MappableCommand 
{

    public void iOverrodeTheEqualsMethod();

    public void seriouslyIPromiseThatIOverrodeIt();

}
回首观望 2024-08-15 21:19:21

以下是其他一些建议解决方案的变体:

public abstract class CommandOverridingEquals implements Command {
    public abstract boolean equals(Object other);
    public abstract int hashcode();
}

Map<String, CommandOverridingEquals> map = 
    new HashMap<String, CommandOverridingEquals>();

或者,如果您确实想确定,请使用经过检查的哈希图;例如,

Map<String, CommandOverridingEquals> map = Collections.checkedMap(
    new HashMap<String, Command>(),
    String.class, CommandOverridingEquals.class);

但无论你做什么,你都无法阻止某人这样做:

public class AntiFascistCommand extends CommandOverridingEquals {
    public boolean equals(Object other) { return super.equals(other); }
    public int hashcode() { return super.hashcode(); }
    ...
}

我倾向于认为这种事情会在以后造成麻烦。例如,假设我有一堆现有的命令类,它们扩展了其他一些基类,并且(顺便说一句)以规定的方式覆盖equalshashcode。问题是,我无法使用这些课程。相反,我被迫重新实现它们或编写一堆包装器。

在我看来,试图强迫开发人员采用特定的实现模式是一个坏主意。最好在 Javadoc 中加入一些强烈的警告,并依赖开发人员做正确的事情

Here's a variation of some of the other proposed solutions:

public abstract class CommandOverridingEquals implements Command {
    public abstract boolean equals(Object other);
    public abstract int hashcode();
}

Map<String, CommandOverridingEquals> map = 
    new HashMap<String, CommandOverridingEquals>();

Or if you really want to be sure, use a checked hashmap; e.g.

Map<String, CommandOverridingEquals> map = Collections.checkedMap(
    new HashMap<String, Command>(),
    String.class, CommandOverridingEquals.class);

But no matter what you do you cannot stop someone doing this:

public class AntiFascistCommand extends CommandOverridingEquals {
    public boolean equals(Object other) { return super.equals(other); }
    public int hashcode() { return super.hashcode(); }
    ...
}

I tend to think that this kind of thing will cause trouble down the track. For example, suppose that I have a bunch of existing command classes that extend some other base class, and (incidentally) override equals and hashcode in the prescribed way. Problem is, I cannot use those classes. Instead, I'm forced to reimplement them or write a bunch of wrappers.

IMO, it is a bad idea to try to force the developer into a particular implementation pattern. It would be better to put some strong warnings into the Javadocs and rely on the developers to do the right thing.

药祭#氼 2024-08-15 21:19:21

您是否可以为相关地图提供您自己的 java.util.comparator

Is it possible for you to provide your own java.util.comparator to the map in question?

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