-1

I can not get this Objects out of a ArrayList I think ArrayList uses the equals method and the hashCode method so I do miss something? This is my Object

public class OPCode {

public String code;

public OPCode(String code){     

    this.code = code;      
}

@Override
public boolean equals(Object o){
 OPCode c = (OPCode) o; 
return this.code.equals(c.code.substring(0, c.code.length()-2)); // returns ture 
}

@Override
public int hashCode() {
   return 1;
}
}

and and example

ArrayList<OPCode> t_codes = new ArrayList();
 OPCode c = new OPCode("1-202");
    t_codes.add(c);
    OPCode e = new OPCode("1-202.0");
    t_codes.indexOf(e); // -1 <-- Problem here 
    t_codes.indexOf(c) // finds it

I want e and c to be equal.

Zion
  • 723
  • 3
  • 7
  • 24
  • possible duplicate of [How do I compare strings in Java?](http://stackoverflow.com/questions/513832/how-do-i-compare-strings-in-java) – Joe Dec 18 '14 at 11:26
  • The way I see it. You ether need to override equals on OPCode or use a wrapper object that has an overridden equals method – AppX Dec 18 '14 at 11:26
  • obviously not a duplicate of how do i compare strings. – kai Dec 18 '14 at 11:34
  • [Beware of how you are using `hashCode()` and `equals()`](http://stackoverflow.com/questions/27581/what-issues-should-be-considered-when-overriding-equals-and-hashcode-in-java). Whenever `a.equals(b)`, then `a.hashCode()` must be same as `b.hashCode()`. – Narmer Dec 18 '14 at 11:35

6 Answers6

2

Your equals() and hashCode() methods are wrong. You are breaking the contract.

If I understood well you want to find the index of e although there is only c in the list, and you want to do so abusing the String#equals() checking equality only for the first 5 letters. So c.code = 1-202, e.code = 1-202.0, doing c.code.equals(e.code.subString(0, e.code.lenght()-2)) should hold true.

This is the correct implementation:

public class OPCode {

    public String code;

    public OPCode(String code){     

        this.code = code;      
    }

    @Override
    public int hashCode() {
        final int prime = 31;
        int result = 1;
        result = prime * result + ((code == null) ? 0 : code.split("\\.")[0].hashCode());
        return result;
    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj)
            return true;
        if (obj == null)
            return false;
        if (getClass() != obj.getClass())
            return false;
        OPCode other = (OPCode) obj;
        if (code == null) {
            if (other.code != null)
                return false;
        } else{
            String thisCode = code.split("\\.")[0];
            String otherCode = other.code.split("\\.")[0];
            if (!thisCode.equals(otherCode))
                return false;
        }
        return true;
    }
}

Note that I used the method String#split since (and this is my assumption) you want to be equal codes with same numerical part without considering decimal part. Using split we avoid managing variable number of literals.

Test it with:

ArrayList<OPCode> t_codes = new ArrayList<OPCode>();
OPCode c = new OPCode("1-202");
t_codes.add(c);
OPCode e = new OPCode("1-202.0");
System.out.println(t_codes.indexOf(e)); // -1 <-- Problem here now gives 0
System.out.println(t_codes.indexOf(c));

BTW I created both method using eclipse built in function via Source>Generate hashCode() and equals()… and modified for the task.

Narmer
  • 1,414
  • 7
  • 16
0

You have not added the element to the list t_codes.add(e);

t_codes.indexOf(c) // finds it works because you have added this object to the list t_codes.add(c);

But you have not added your object OPCode e = new OPCode("1-202.0"); to the list. Therefore t_codes.indexOf(e); gives you -1

gprathour
  • 14,813
  • 5
  • 66
  • 90
  • 1
    I'm not the downvoter, but your answer doesn't solve OPs problem. I guess that is why you've got downvoted. – Tom Dec 18 '14 at 11:53
  • @Tom Okay, but I think OP was having problem because he forgot to add second object to the list. – gprathour Dec 18 '14 at 11:55
  • 1
    No. He added `c` and he want his program (or the `indexOf` method) to return the index of `c` if he passes `e` to the `indexOf` method. – Tom Dec 18 '14 at 11:58
0

If you are working with Eclipse. Select the method and press F3 (jdk required). Now you will see implementation:

/**
 * 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 <tt>i</tt> such that
 * <tt>(o==null&nbsp;?&nbsp;get(i)==null&nbsp;:&nbsp;o.equals(get(i)))</tt>,
 * or -1 if there is no such index.
 */
public int indexOf(Object o) {
    if (o == null) {
        for (int i = 0; i < size; i++)
            if (elementData[i]==null)
                return i;
    } else {
        for (int i = 0; i < size; i++)
            if (o.equals(elementData[i]))
                return i;
    }
    return -1;
}
alex
  • 8,904
  • 6
  • 49
  • 75
0

Problem is with your equals method.

t_codes.indexOf(c) is actually referring to object e. Because as per your equals method implementation, e is equal to c, but vice versa is not true.

your e.equals(c) != c.equals(e). You need to revisit equals implementation.

codingenious
  • 8,385
  • 12
  • 60
  • 90
0

Your equals() method is not commutative. I.e. e.equals(c) != c.equals(e), so it's not unexpected that you get strange behaviour.

Petter
  • 4,053
  • 27
  • 33
0

Problem is with your equals method.

return (c.code.equals(code)) || c.code.equals(this.code.substring(0, this.code.length() - 2));
Reinaldo Gil
  • 630
  • 5
  • 11