ArrayList和HashSet中contains方法的不同

来源:互联网 发布:javascript dom对象 编辑:程序博客网 时间:2024/05/16 03:47

ArrayList和HashSet中contains方法的不同

首先来看一道笔试题:

view plaincopy to clipboardprint?import java.util.ArrayList; 
 
import java.util.HashSet; 
 
public class Foo { 
 
   int value; 
 
   Foo(int value) { 
 
      this.value = value; 
 
   } 
 
public boolean equals(Object obj) { 
 
     if (obj instanceof Foo) { 
 
       Foo foo = (Foo) obj; 
 
       return value == foo.value; 
 
     } else { 
 
        return false; 
 
     } 
 
  } 
 
   /**
public int hashCode() {

         return this.value;

   }

*/ 
 
   public static void main(String... args) { 
 
      ArrayList list = new ArrayList(); 
 
      HashSet set = new HashSet(); 
 
       
 
      Foo f1 = new Foo(1); 
 
      Foo f2 = new Foo(1); 
 
      list.add(f1); 
 
      set.add(f2); 
 
       
 
      Foo f3 = new Foo(1); 
 
      Foo f4 = new Foo(1); 
 
      System.out.println(list.contains(f3) + "," + set.contains(f4)); 
 
   } 
 

import java.util.ArrayList;

import java.util.HashSet;

public class Foo {

   int value;

   Foo(int value) {

      this.value = value;

   }

public boolean equals(Object obj) {

     if (obj instanceof Foo) {

       Foo foo = (Foo) obj;

       return value == foo.value;

     } else {

        return false;

     }

  }

   /**
public int hashCode() {

         return this.value;

   }

*/

   public static void main(String... args) {

      ArrayList list = new ArrayList();

      HashSet set = new HashSet();

     

      Foo f1 = new Foo(1);

      Foo f2 = new Foo(1);

      list.add(f1);

      set.add(f2);

     

      Foo f3 = new Foo(1);

      Foo f4 = new Foo(1);

      System.out.println(list.contains(f3) + "," + set.contains(f4));

   }

}

答案:true,false   打开注释后,结果为:true ,true



下面分析为什么,我们先看看JDK中ArrayList的方法contains()的源代码:

view plaincopy to clipboardprint?public boolean contains(Object o) { 
 
      return indexOf(o) >= 0; 
 

public boolean contains(Object o) {

      return indexOf(o) >= 0;

}


其中调用了indexOf(),我们接着看,

view plaincopy to clipboardprint?public int indexOf(Object o) { 
 
if (o == null) { 
 
       for (int i = 0; i < size; i++) 
 
      if (elementData[i]==null) 
 
          return i;//如果o为空且集合中i位置处也为空,返回i  
 
   } else { 
 
       for (int i = 0; i < size; i++) 
 
      if (o.equals(elementData[i])) 
 
          return i;//如果o不为空,且集合中i位置对象equals对象o,返回i  
 
   } 
 
   return -1;//否则返回-1  
 

public int indexOf(Object o) {

if (o == null) {

       for (int i = 0; i < size; i++)

      if (elementData[i]==null)

          return i;//如果o为空且集合中i位置处也为空,返回i

   } else {

       for (int i = 0; i < size; i++)

      if (o.equals(elementData[i]))

          return i;//如果o不为空,且集合中i位置对象equals对象o,返回i

   }

   return -1;//否则返回-1

}


所以,因为list中有对象f1,而f1.equals(f3)为true,所以执行indexOf()方法返回0,执行contains()返回true;

在来看HashSet中contains()方法源代码:

view plaincopy to clipboardprint?public boolean contains(Object o) { 
 
      return map.containsKey(o); 
 

 
public boolean containsKey(Object key) { 
 
       return getEntry(key) != null; 
 

 
final Entry<K,V> getEntry(Object key) { 
 
        int hash = (key == null) ? 0 : hash(key.hashCode()); 
 
        for (Entry<K,V> e = table[indexFor(hash, table.length)]; 
 
             e != null; 
 
             ee = e.next) { 
 
            Object k; 
 
            if (e.hash == hash && 
 
                ((k = e.key) == key || (key != null && key.equals(k)))) 
 
                return e; 
 
        } 
 
       return null; 
 

public boolean contains(Object o) {

      return map.containsKey(o);

}

public boolean containsKey(Object key) {

       return getEntry(key) != null;

}

final Entry<K,V> getEntry(Object key) {

        int hash = (key == null) ? 0 : hash(key.hashCode());

        for (Entry<K,V> e = table[indexFor(hash, table.length)];

             e != null;

             e = e.next) {

            Object k;

            if (e.hash == hash &&

                ((k = e.key) == key || (key != null && key.equals(k))))

                return e;

        }

       return null;

}


由于Foo类中重写了equals()而没有重写hashCode()方法,所以会执行父类Object 中的 hashCode 方法,(会针对不同的对象返回不同的整数,具体是将该对象的内部地址转换成一个整数来实现的),由于f2和f4内存地址不同,所以hashcode也不同,所以执行getEntry()方法返回null,执行containsKey返回false,当然的执行contains()也会返回false;

综上所述:对于一个类重写了equals()方法后,重写它的hashCode()方法是必要的,以维护 hashCode 方法的常规协定:相同的对象必须具有相等的哈希码。

 

原创粉丝点击