3

I tried the following simple test.

class ZiggyTest{
    public static void main(String[] args){

        List<Cities> cities3 = new ArrayList<Cities>();
        Cities city = new Cities("London");

        cities3.add(new Cities("Manchester"));
        cities3.add(new Cities("Glasgow"));
        cities3.add(new Cities("Leeds"));
        cities3.add(city);
        cities3.add(new Cities("Leicester"));
        cities3.add(new Cities("Croydon"));
        cities3.add(new Cities("Watford"));

        System.out.println("IndexOf(new Croydon) " 
                       + cities3.indexOf(new Cities("Croydon")));
        System.out.println("IndexOf(city) " 
                       + cities3.indexOf(city));
    }   
}

class Cities implements Comparable<Cities>{
    String title;

    Cities(String aTitle){
        this.title = aTitle;
    }

    public String getTitle(){
        return title;
    }

    public String toString(){
        return "Title : " + title;
    }

    public int compareTo(Cities c){
        return title.compareTo(c.getTitle());
    }
}

The output of the above test is

IndexOf(new Croydon) -1
IndexOf(city) 3

I understand why the second line is producing 3 but I don't understand why the first line is not finding the new one with title="Croydon".

The API describes the indexOf method as one that

Returns the index of the first occurrence of the specified element in this list, or -1 if this list does not contain the element. More formally, returns the lowest index i such that (o==null ? get(i)==null : o.equals(get(i))), or -1 if there is no such index.

I think the API is saying that if the object is null then it will return the index of the first occurrence of a null object from the list. If it is not null it will return the index of the first occurrence where the passed in object equals method returns true.

Shouldn't the the object created as cities3.indexOf(new Cities("Croydon") be equal to the object added previously as cities3.add(new Cities("Croydon"));?

serv-inc
  • 35,772
  • 9
  • 166
  • 188
ziggy
  • 15,677
  • 67
  • 194
  • 287
  • 2
    Perhaps it's Java's desire to forget about Croydon? Can't really blame it for that... (See mishadoff's answer for the real solution, but as an old Whitgiftian, I couldn't resist...) – Jon Skeet Oct 30 '11 at 13:20

2 Answers2

11

Redefine equals instead of compareTo if you want perform search operations.

By default indexOf compares using equals operation, and in your case equals not redefined, that means you have comparison by references. When you create new City object with the same name you have another reference to object, so equals return false.

P.S. If you are using object that describe city, preferable name for class City not Cities

mishadoff
  • 10,719
  • 2
  • 33
  • 55
  • 1
    Indeed. Defining an `equals()` override will resolve the `indexOf()` issue. @ziggy: do note that you can't override `equals()` without also overriding `hashCode()`. If you fail to do that, the "objects that are equal according to `equals()` must have the same `hashCode()`" requirement is violated. – Barend Oct 30 '11 at 13:20
  • Thanks. In what situation would the compareTo() be useful then? I thought that it would work because String does override equals(). – ziggy Oct 30 '11 at 13:33
  • compareTo() useful when you perform sorting operation not by natural order, or when you are using SortedSet. String override equals, but your class City not. – mishadoff Oct 30 '11 at 13:37
-1

In Swift 5.3, if your object inherits from NSObject, you'll need to do this:

The method name is "isEqual"

public override func isEqual(_ object: Any?) -> Bool {
    if let myObj = object as? MyObj {
        return myObj.someProperty == self.someProperty
    }
    return false
}
TheJeff
  • 3,665
  • 34
  • 52