简体   繁体   中英

Add no duplicates to List of supperclass (check for equality with subclasses)

I have a List<Item> items = new ArrayList<>(); I add two different Items to, both subclasses of Item : PortableItem and SceneryItem .

public class Item implements Comparable<item> {
    public String id;
    public String desc;

    ...

    public int compareTo(Item o) {
        return getId().compareTo(o.getId());
    }  
}

Now I would like to detect Items with duplicate ID s before adding a new one to my List.

    PortableItem a = new PortableItem("a");
    SceneryItem b  = new SceneryItem("a");
    items.add(a);
    items.contains(b); 

Returns false. How can I change that behavior?

You could add an equals method that compared on id, be default an Object equals another when they are == - ie the same instance. This isn't what you want.

public class Item implements Comparable<Item> {

    public String id;
    public String desc;

    public String getId() {
        return id;
    }

    @Override
    public int compareTo(Item o) {
        return getId().compareTo(o.getId());
    }

    @Override
    public int hashCode() {
        int hash = 7;
        hash = 17 * hash + Objects.hashCode(this.id);
        return hash;
    }

    @Override
    public boolean equals(Object obj) {
        if (obj == this) {
            return true;
        }
        if (!(obj instanceof Item)) {
            return false;
        }
        final Item other = (Item) obj;
        if (!Objects.equals(this.id, other.id)) {
            return false;
        }
        return true;
    }
}

This is really good practice anyway given your compareTo method and the requirement that is is consistent with equals - now a.equals(b) will return true if they have the same id .

As you now have an equals method you have to have a hashCode() method, again the consistent with equals requirement.

Note that if you override the equals method in a superclass this obviously won't work unless you use a call to return super.equals at the end.

Now, using a List the contains method is guaranteed O(n) - this is very slow . I would recommend using a Set where contains is guaranteed O(1). If you need to maintain order use a LinkedHashSet or even better a TreeSet which will use your compareTo method to order items automagically.

You can always turn the thing into a List afterwards with one O(n) call anyway...

You need to override the equals() and hashCode() methods in the base class to compare by ID.
compareTo() is only used for sorting.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM