重写 equals 方法而不破坏具有主键的类中的对称性

发布于 2024-08-30 23:18:30 字数 1300 浏览 5 评论 0原文

这个问题的答案可能是“不可能”,但无论如何让我问:)

假设我们有一个非常简单的JAVA类,它有一个主键,例如:

class Person {
    String ssid;
    String name;
    String address;
    ...
}

现在,我想将人存储在一个集合中,这意味着我将必须重写 equals 方法。这不是一件完全微不足道的事情,但在简单的基础上,我会得到一些类似的东西:

@Override
public boolean equals (Object other) {
    if(other==this) return true;
    if(!other.getClass().equals(this.getClass()) return false;
    Person otherPerson = (Person)other;
    if(this.ssid.equals(otherPerson.getSsid()) return true;
}

请原谅任何明显的错误,只是从我的脑海中输入这个。现在,假设稍后在应用程序中我有一个通过用户输入获得的 ssid。如果我想将我的 ssid 与一个人进行比较,我必须调用类似的方法:

String mySsid = getFromSomewhere();
Person myPerson = getFromSomewhere();
if(myPerson.equals(new Person(mySsid)) doSomething();

这意味着我必须创建一个方便的构造函数来创建一个基于 ssid 的人(如果我还没有),而且它也很方便冗长。简单地调用会更好

myPerson.equals(mySsid)

,但如果我向 Person equals 类添加字符串比较,这会破坏对称性,因为 String 没有关于如何将自身与 Person 进行比较的线索。

所以最后,一个大问题是,有没有什么方法可以使用重写的 equals 方法来启用这种“速记”比较,并且不破坏对称规则?

感谢您对此的任何想法!

编辑:只是为了澄清,这更像是一个悬而未决的问题,而不是寻求确切解决方案的问题。当我想从集合中提取 Person 时, equals 应该满足这种情况。因此应该可以做这样的事情:

List<Person> people = ...
people.get(ssid);

能够基于主键在类上定义相等性似乎是显而易见且直观的,但我还没有找到一种简单的方法来做到这一点。

the answer to this question is probably "not possible", but let me ask regardless :)

Assuming we have a very simple JAVA class that has a primary key, for example:

class Person {
    String ssid;
    String name;
    String address;
    ...
}

Now, I want to store people in a collection, meaning I will have to override the equals method. Not a completely trivial matter, but on a bare basis I will have something along the lines of:

@Override
public boolean equals (Object other) {
    if(other==this) return true;
    if(!other.getClass().equals(this.getClass()) return false;
    Person otherPerson = (Person)other;
    if(this.ssid.equals(otherPerson.getSsid()) return true;
}

Excuse any obvious blunders, just typing this out of my head. Now, let's say later on in the application I have a ssid I obtained through user input. If I want to compare my ssid to a Person, I would have to call something like:

String mySsid = getFromSomewhere();
Person myPerson = getFromSomewhere();
if(myPerson.equals(new Person(mySsid)) doSomething();

This means I have to create a convenience constructor to create a Person based on ssid (if I don't already have one), and it's also quite verbose. It would be much nicer to simply call

myPerson.equals(mySsid)

but if I added a string comparison to my Person equals class, that would break the symmetry property, since the String hasn't got a clue on how to compare itself to a Person.

So finally, the big question, is there any way to enable this sort of "shorthand" comparisons using the overriden equals method, and without breaking the symmetry rule?

Thanks for any thoughts on this!

EDIT: Just to clarify, this is more of an open question than a problem seeking an exact solution. The equals should cater for cases when I want to extract a Person from a collection. So it should be possible to do something like this:

List<Person> people = ...
people.get(ssid);

It would appear obvious and intuitive to be able to define equality on a class based on a primary key, but I haven't found a straightforward way of doing that.

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

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

发布评论

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

评论(6

无言温柔 2024-09-06 23:18:30

更好的选择是将您的人员存储在地图中,然后您可以轻松检索它们:

HashMap<String, Person> people = new HashMap<String, Person>();

Person p = constructPersonFromStuff();

people.put(p.ssid, p);

然后,您可以查看该人是否存在:

String ssid = getFromSomewhere();

if(people.contains(ssid)){
  Person thatGuy = people.get(ssid);
}else{
  //that person DOESN'T EXIST! HE'S A FIGMENT OF YOUR IMGAINATION!
}

A better bet is to store your People in a map, then you can retrieve them easily:

HashMap<String, Person> people = new HashMap<String, Person>();

Person p = constructPersonFromStuff();

people.put(p.ssid, p);

and then later, you can see if the person exists:

String ssid = getFromSomewhere();

if(people.contains(ssid)){
  Person thatGuy = people.get(ssid);
}else{
  //that person DOESN'T EXIST! HE'S A FIGMENT OF YOUR IMGAINATION!
}
空心空情空意 2024-09-06 23:18:30

您不是在比较两个 Person,而是在比较两个 ssid。我会用:

myPerson.getSsid().equals(mySsid);

You're not comparing two Persons, you're comparing two ssids. I would use:

myPerson.getSsid().equals(mySsid);
诗化ㄋ丶相逢 2024-09-06 23:18:30

Person 等于字符串是没有意义的,不要走这条路。

我只是不明白你的问题。你有这样的代码:

String mySsid = getFromSomewhere();
Person myPerson = getFromSomewhere();
if (myPerson.getSsid().equals(mySsid) doSomething();

这对我来说看起来还不错。我想你可以定义一个函数来为你做到这一点:

if (myPerson.ssidEquals(mySsid)) doSomething();

但这实际上并不是那么大的改进。

有什么问题吗?

It makes no sense to say that a Person is equal to a string, do not go down that path.

I just don't understand your problem. You have this code:

String mySsid = getFromSomewhere();
Person myPerson = getFromSomewhere();
if (myPerson.getSsid().equals(mySsid) doSomething();

That just doesn't look bad to me. I guess you could define a function to do that for you:

if (myPerson.ssidEquals(mySsid)) doSomething();

But that's really not that big improvement.

What's the problem?

贪恋 2024-09-06 23:18:30

我认为 Person 不等于 ssid。事实上,使用 ssid 比较来确定两个人是否相等是一种捷径——我们认为具有相同 ssid 的两个人指代现实世界中的同一个人是一种约定——但实际上并不是相等的原因真的。

也许您真正想要的是为您的 Person 提供一个布尔值“hasSsid()”方法。或者直接调用myPerson.getSsid().equals(mySsid)

I'd argue that a Person isn't equal to an ssid. The fact that you use ssid comparison to determine whether two Persons are equal is a shortcut -- we accept as a convention that two Persons with the same ssid refer to the same real-world person -- but isn't actually what makes the equality true.

Perhaps what you really want here is to give your Person a boolean "hasSsid()" method. Or just call myPerson.getSsid().equals(mySsid).

浅语花开 2024-09-06 23:18:30

当 equals 方法的参数不是调用该方法的类的实例时,它绝不能返回 true。

如果您愿意,您可以创建一个界面,例如“可识别”。

public interface Identifiable {
    public Serializable getSsid();
}

public class Person implements Identifiable { ...

然后,您可以根据可识别的通用方式编写代码......这可能会有所帮助。

(我假设真正的问题是以通用方式处理实用例程等的可识别对象)。

the equals method must never return true when its argument is not an instance of the class on which the method was invoked.

if you like, you can create an interface, say Identifiable.

public interface Identifiable {
    public Serializable getSsid();
}

public class Person implements Identifiable { ...

you can then write your code in a generic way in terms of Identifiable ... this might help.

(i'm assuming that the real problem is to handle your identifiable objects in a generic fashion for utility routines and such).

甜`诱少女 2024-09-06 23:18:30

您可以创建一个使用映射或内部设置的自定义数据结构:

public interface EntityStore<T,K> {
    T get(K id);
    boolean contains(Object o);
    void put(K id, T entity);
    void remove(Object o);
    // ...
}

public class MapEntityStore<T,K> {
    private Map<K,T> entities = new HashMap<K,T>();
    public T get(K id) { return entities.get(id); }
    public boolean contains(Object o) {
        if (entities.keySet().contains(o))
            return true; // search by id
        if(entities.values().contains(o))
            return true; // search by value (this can be optimized if necessary)

        return false;
    }
    ...
}

您可以使用工厂方法来创建 EntityStore 的实例,以便您可以根据需要更改为优化/奇特的实现。

You could create a custom data structure that uses a map or set internally:

public interface EntityStore<T,K> {
    T get(K id);
    boolean contains(Object o);
    void put(K id, T entity);
    void remove(Object o);
    // ...
}

public class MapEntityStore<T,K> {
    private Map<K,T> entities = new HashMap<K,T>();
    public T get(K id) { return entities.get(id); }
    public boolean contains(Object o) {
        if (entities.keySet().contains(o))
            return true; // search by id
        if(entities.values().contains(o))
            return true; // search by value (this can be optimized if necessary)

        return false;
    }
    ...
}

You can use a factory method to create instances of EntityStore so that you can change to optimized / fancy implementations as necessary.

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