Java: как написать правильный метод equals для классов, которые действительно не имеют никакого состояния? - PullRequest
4 голосов
/ 14 июня 2011

Рассмотрим этот интерфейс:

public interface Listenable {
  void listen();
}

Рассмотрим эту реализацию:

public class Listener implements Listenable {
  public void listen() {
    System.out.println("I am listening");
  }
}

Сейчас я выполняю удаленное взаимодействие через RMI и передаю экземпляры таких классов на сервер (возможно, черный-магические прокси появляются там, не уверен).

Единственное решение, которое я смог до сих пор изобрести, , и я должен сказать, что это довольно идиотский , это добавить этот код в Listenerкласс:

public class Listener implements Listenable {
  private double id;
  private Random rand = new Random();
  public Listener() {
    this.id = rand.nextDouble();
  }
  public void listen() {
    System.out.println("I am listening");
  }
  public int hashCode() { ... } // calculate from id
  // same for equals - compare by id
}

Это обычно работает, но мы все знаем, насколько это зло: / Как следует иметь дело с такой ситуацией?

ОБНОВЛЕНИЕ:

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

Ответы [ 4 ]

7 голосов
/ 14 июня 2011

Сделать слушателя синглтоном enum:

public enum Listener implements Listenable {
  INSTANCE;

  public void listen() {
    System.out.println("I am listening");
  }
}

Тогда будет только один экземпляр Listener, и равенство гарантировано.

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

public static Listenable printingListenable() {
  return Listener.INSTANCE;
}
4 голосов
/ 14 июня 2011

ИМХО равенство объектов определяется равенством их состояния. Если объект не содержит какого-либо состояния (возможно, его не следует называть объектом, но это другая история), все экземпляры этого объекта логически равны. Так что не беспокойтесь и напишите:

public boolean equals(Object obj) {
  return obj instanceof Listener;
}

public int hashCode() {
  return 0;
}
2 голосов
/ 14 июня 2011

Поскольку слушатель полностью лишен состояния, для многих практических целей разные экземпляры могут рассматриваться как одна и та же личность. Одним словом, сам класс будет определять личность. Так как насчет этого:

public boolean equals(Object obj) {
   return obj!=null&&obj.getClass().equals(this.getClass());
 }

 public int hashCode() {
   return 0;
 }
}

Меня беспокоит instanceof, поскольку подклассы могут не считаться одним и тем же объектом.

1 голос
/ 14 июня 2011

Если объекты не имеют какого-либо состояния, то все они должны быть равны. Почему нужно различать их?

...