Подтвердить что ты не робот

Принудительный класс для переопределения метода .equals

У меня есть куча класса, который реализует общий интерфейс: Command.

И эта группа классов переходит на карту.

Чтобы карта работала правильно, мне нужен каждый класс, который реализует команду для переопределения метода Object.equals(Object other).

это нормально.

Но я бы хотел заставить переопределение равных. = > Имейте ошибку компиляции, когда что-то, кто реализует команду, не переопределяет значения.

Это возможно?

Изменить: BTW, мне также потребуется принудительно переопределить hashcode...

4b9b3361

Ответ 1

Нет, вы не можете. Однако вы можете использовать абстрактный базовый класс вместо интерфейса и сделать equals() abstract:

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 ошибочно ошибаются.

Ответ 2

Можете ли вы расширить свои объекты из абстрактного объекта XObject, а не java.lang.Object?

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

Ответ 3

Абстрактные классы не будут работать, если у вас есть внук, так как его отец уже переопределил оба метода equals и hashCode, а затем снова возникла ваша проблема.

Попробуйте использовать аннотатины и APT (http://docs.oracle.com/javase/1.5.0/docs/guide/apt/GettingStarted.html), чтобы сделать это.

Ответ 4

Это было бы возможно только в том случае, если Command был интерфейсом или абстрактным классом, где equals (..) - это метод, объявленный как абстрактный.

Проблема заключается в том, что Object, являющийся суперклассом всех объектов, уже определяет этот метод.

Если вы хотите указать, что это проблема (во время выполнения), вы можете создать исключение, чтобы заставить пользователей вашего API переопределить его. Но это невозможно во время компиляции, по крайней мере, насколько мне известно.

Попытайтесь обойти его, используя специфичный для API метод, например. CommandEquals. Другой вариант (как упоминалось) расширяет другой класс, который определяет абстрактный метод Equals.

Ответ 5

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.");
    }
}

Ответ 6

Хорошо, если вы хотите проверить время выполнения, вы можете сделать что-то вроде:

    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 для второго. Если вы хотите, чтобы время компиляции выглядело как единственная опция, это создать аннотацию и использовать инструмент обработки аннотаций, чтобы проверить, что все аннотированные классы переопределяются равными.

Ответ 7

Так как equals() наследуется от Object, я сомневаюсь, что вы действительно не можете это сделать, поскольку для каждого типа существует автоматическая унаследованная реализация equals().

Ответ 8

Я не думаю, что можно принудительно переопределить равные числа, как это происходит из класса Object.

В соответствующей заметке обратите внимание, что вам нужно переопределить метод hashCode из класса Object, когда вы переопределяете равные. Это становится особенно важным, если вы собираетесь использовать экземпляры ваших классов в качестве ключей Карты. Проверьте эту статью: http://www.artima.com/lejava/articles/equality.html который дает некоторые подсказки о том, как правильно переопределить равные значения.

Ответ 9

Как уже объяснили другие ответы, вы не можете заставить то, что вы пытаетесь сделать.

Одна вещь, которая может работать "достаточно", - это определить второй интерфейс, вызвать этот MappableCommand.

public interface MappableCommand 
{

}

В вашей документации для этого интерфейса указывается, что класс должен реализовывать этот (пустой) интерфейс, если разработчик класса рассмотрел требования, которые вы указали.

Затем вы можете установить тип значения вашей карты в MappableCommand, и только MappableCommands смогут быть добавлены на карту.

Это похоже на логику того, почему нужно реализовать (пустой) интерфейс Serializable для классов, которые могут быть сериализованы механизмами сериализации Java по умолчанию.

Если это не сработает, вам может потребоваться решить проблему с ошибкой времени выполнения;

Fake Edit:

Если вы хотите сделать это требование более очевидным, вы можете определить новый интерфейс таким образом

public interface MappableCommand 
{

    public void iOverrodeTheEqualsMethod();

    public void seriouslyIPromiseThatIOverrodeIt();

}

Ответ 10

Вы можете создать boolean myEquals() в interface Command и создать Adapter следующим образом:

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

Затем вы просто используете map.put(key, new MyAdapter(command)) вместо map.put(key, command)

Ответ 11

Здесь вариация некоторых других предложенных решений:

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

Я склонен думать, что подобные вещи вызовут проблемы на дорожке. Например, предположим, что у меня есть куча существующих классов команд, которые расширяют некоторый другой базовый класс и (кстати) переопределяют equals и hashcode заданным образом. Проблема в том, что я не могу использовать эти классы. Вместо этого я вынужден переопределить их или написать кучу оберток.

IMO, неплохо попытаться заставить разработчика проявить конкретный образец реализации. Было бы лучше вставить некоторые сильные предупреждения в Javadocs и полагаться на разработчиков, чтобы они поступали правильно.

Ответ 12

Возможно ли, чтобы вы предоставили свой собственный java.util.comparator на соответствующую карту?