ArrayList not using the overridden equals

后端 未结 11 1381
误落风尘
误落风尘 2021-02-08 14:13

I\'m having a problem with getting an ArrayList to correctly use an overriden equals. the problem is that I\'m trying to use the equals to only test for a single key field, and

相关标签:
11条回答
  • 2021-02-08 15:01

    Your equals implementation is wrong. Your in parameter should not be a String. It should be an InnerClass.

    public boolean equals(Object o) {
      if (this == o) return true;
      if (!(o instanceof InnerClass) return false;
      InnerClass that = (InnerClass)o;
      // check for null keys if you need to
      return this.testKey.equals(that.testKey);
    }
    

    (Note that instanceof null returns false, so you don't need to check for null first).

    You would then test for existence of an equivalent object in your list using:

    objectList.contains(new InnerClass("UNIQUE ID1"));
    

    But if you really want to check for InnerClass by String key, why not use Map<String,InnerClass> instead?

    0 讨论(0)
  • 2021-02-08 15:04

    You're invoking contains with an argument that's a String and not an InnerClass:

    System.out.println( objectList.contains("UNIQUE ID1"))
    

    In my JDK:

    public class ArrayList {
    
        public boolean contains(Object o) {
        return indexOf(o) >= 0;
        }
    
        public int indexOf(Object o) {
        if (o == null) {
            // omitted for brevity - aix
        } else {
            for (int i = 0; i < size; i++)
            if (o.equals(elementData[i])) // <<<<<<<<<<<<<<<<<<<<<<
                return i;
        }
        return -1;
        }
    }
    

    Note how indexOf calls o.equals(). In your case, o is a String, so your objectList.contains will be using String.equals and not InnerClass.equals.

    0 讨论(0)
  • 2021-02-08 15:08

    in the other way, your equal method gets called if you change your code as follows. hope this clears the concept.

    package com.test;
    
    import java.util.ArrayList;    
    import java.util.List;
    
    public class TestClass  {
        private static class InnerClass{    
            private final String testKey;
            //data and such
    
            InnerClass(String testKey, int dataStuff) {
                this.testKey =testKey;
                //etc
            }
    
            @Override
            public boolean equals (Object in1) {
                System.out.println("reached here");
                if(in1 == null) {
                    return false;
                }else if( in1 instanceof InnerClass) {
                    return ((InnerClass) this).testKey == null ? false : ((InnerClass) this).testKey.equals(((InnerClass) in1).testKey);
                }else {
                    return false;
                }       
            }       
        }
    
        public static void main(String[] args) {    
            ArrayList<InnerClass> objectList = new ArrayList<InnerClass>();
            InnerClass in1 = new InnerClass("UNIQUE ID1", 42);
            InnerClass in2 = new InnerClass("UNIQUE ID1", 42);
    
            //add some entries
            objectList.add(in1);
            System.out.println( objectList.contains(in2)); 
        }    
    }
    
    0 讨论(0)
  • 2021-02-08 15:09

    If you check sources of ArrayList, you will see that it calls equals of other object. In your case it will call equals of String "UNIQUE ID1" which will check that other object is not of type String and just returns false:

    public boolean contains(Object o) {
        return indexOf(o) >= 0;
    }
    
    public int indexOf(Object o) {
        ...     
        for (int i = 0; i < size; i++)
        if (o.equals(elementData[i]))
            return i;
        ...
        return -1;
    }
    

    For your case call contains with InnerClass that only contains id:

    objectList.contains(new InnerClass("UNIQUE ID1"))
    

    Don't forget to implement equals for InnerClass which compares id only.

    0 讨论(0)
  • 2021-02-08 15:10

    Although not answering your question, many Collections use hashcode(). You should override that too to "agree" with equals().

    Actually, you should always implement both equals and hashcode together, and they should always be consistent with each other. As the javadoc for Object.equals() states:

    Note that it is generally necessary to override the hashCode method whenever this method is overridden, so as to maintain the general contract for the hashCode method, which states that equal objects must have equal hash codes.

    Specifically, many Collections rely on this contract being upheld - behaviour is undefined otherwise.

    0 讨论(0)
提交回复
热议问题