为什么这个代码的结果会是随机的?

import java.util.ArrayList;
import java.util.Date;
import java.util.List;

public class Demo01 {

     public static void main(String[] args) {
          List list=new ArrayList();
//          Date d1=new Date();
//          Date d2=new Date();
          list.add("aa");
          list.add(new Date());
          System.out.println("移除前:"+list.size());
          list.remove("aa");
          list.remove(new Date());
          System.out.println("移除后:"+list.size());         
     }
}

我的结果是
2
0
或者
2
1
如果代码结果没有随机,把注释的两行代码先执行一遍再注释掉,就会随机出现上面2中结果了


已经得到解答,就是hashcode和equals被重写了后跟当前时间有关,偶尔运行太快就new出来的两个Date的getTime()就一样了,谢谢大家

阅读 2.8k
3 个回答

这是一个很好的基础问题,包含了对equals方法的理解,以及ArrayList的remove方法的理解。
为何remove("aa")就能够将add进去的"aa"给移除了,而new进去的Date却不能,还看似有随机性呢。
顺着这样的思考思路,就应该去查看ArrayList的remove方法。

public boolean remove(Object o) {
        if (o == null) {
            for (int index = 0; index < size; index++)
                if (elementData[index] == null) {
                    fastRemove(index);
                    return true;
                }
        } else {
            for (int index = 0; index < size; index++)
                if (o.equals(elementData[index])) {
                    fastRemove(index);
                    return true;
                }
        }
        return false;
    }
    

通过源码查看能够看到,ArrayList的remove方法是要通过你所传进去的对象的equals来进行判断的,如果equals方法返回的是True那么就认定这两个对象是“相等”的,所以问题就转化为“Date的equals方法是如何判断两个对象相同的”。接下来查看Date的equals方法源码

public boolean equals(Object obj) {
        return obj instanceof Date && getTime() == ((Date) obj).getTime();
    }
    

看上面的代码十分简单,不用多说了,就是根据getTime()返回的毫秒数来判断的,虽然问题比较简单,但是这样思考问题的方式希望能够分享给提问的朋友。

public boolean remove(Object o) {

 if (o == null) {
         for (int index = 0; index < size; index++)
     if (elementData[index] == null) {
         fastRemove(index);
         return true;
     }
 } else {
     for (int index = 0; index < size; index++)
     if (o.equals(elementData[index])) {
         fastRemove(index);
         return true;
     }
     }
 return false;
 }

这是ArrayList的源码,首先通过代码可以看到,当移除成功后返回true,否则返回false。remove(Object o)中通过遍历element寻找是否存在传入对象,一旦找到就调用fastRemove移除对象。你两次new date()的不是一个对象。找不到肯定不会remove。你可以在代码中间加上sleep试试

试了一下,是可能会出现。
看Date的默认构造函数是

 public Date() {
     this(System.currentTimeMillis());
 }

即使用当前的时间作为参数,所以执行时间太短的时候可能会导致两个new Date()实例化两个相等的对象。
Date的equals()方法较复杂,没有仔细分析。不过知道这些,应该差不多了吧。

测试了一下:代码如下:

    list.add("aa");
    list.add(new Date());
    System.out.println(System.currentTimeMillis());
    System.out.println("移除前:"+list.size());
    list.remove("aa");
    list.remove(new Date());
    System.out.println(System.currentTimeMillis());
    
    一次结果为:
    1448642796820
    移除前:2
    1448642796821
    移除后:1
    
    另外一次结果为:
    1448642884334
    移除前:2
    1448642884334
    1448642884334
    1448642884334
    移除后:0

   
撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题