原博地址http://blog.csdn.net/zhaizu/article/details/38556241
如果 Object o 非 null,那么 o.equals(null) 恒等于 false,即 null 不等于任何非 null 对象。
====================
更新于 2016年01月25日,添加 ArrayList.remove(Object ojb) 部分。
==================
首先,equals()是个方法,在祖先类Object中已经实现,源代码如下:
public boolean equals(Object obj) { urn (this == obj); }
== 是个运算符,表示内存地址是否相同。 从Object类中equals的实现可以看出,原始的equals方法跟==是等价的。
先对Java 中的各种数据类型进行一一说明。
基本数据类型
如 byte, char, short, int, long, float, double, boolean等基本数据类型,== 就是表示数量相等,由于不是对象,所以不能使用equals()方法,但是其Integer, Float类可以使用。
对象
如Integer,String和用户自定义的类,== 表示其内存地址是否相同。
其中,String是一个特例,具体见如下代码:
String foo = "loveu" ; String bar = "loveu" ; System.out.println(foo == bar); System.out.println(foo.equals(bar));
上述代码中,第1段中,2个的"loveu"是字符串常量,存放在常量池里,共用1块内存空间,所以内存地址相同,== 结果为true,String类里的equals方法已经被重写,只要内容相同,返回就为true(具体请参见其源代码),所以equals的结果也为true;第2段代码中,新建2个字符串对象,内存地址不同,内容相同,故结果分别为false和true。
自定义类
要重写equals方法,有2种方法实现:
如果使用Eclipse,在自定义类右击——Source——Generate hashCode() and equals(),选择该类相应的成员作为标准,即可生成equals()和hashCode()(hashCode()和equals()是成对出现的,一定要同时重写,同时要重写hashCode()是可以保证对象的功能兼容于hash集合。这是一个好习惯,即使这些对象不会被存储在hash集合中。); 自定义equals(),根据具体业务需要,编写判重标准(注意:因为是重写,equals()的形参一定保持为Object类型,否则重写无效,可以用 @override 来修饰重写方法,如果重写不合法,编译时会报错);
举个列子,自定义类News,有成员变量url,2个url相同的News对象,认为是相等的。使用上述两种重写equals的方式,可得代码:
方式1
@Override public int hashCode() { final int prime = 31 ; int result = 1 ; result = prime * result + ((url == null ) ? 0 : url.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 ; VolatileTest other = (VolatileTest) obj; if (url == null ) { if (other.url != null ) return false ; } else if (!url.equals(other.url)) return false ; return true ; }
方式2
@Override public int hashCode() { final int prime = 100 ; int result = 1 ; result = prime * result + ((url == null ) ? 0 : url.hashCode()); return result; } @Override public boolean equals (Object o) { if (o == null || (o instanceof News) == false ) { return false ; } else { News n = (News) o; return url.equals(n.getUrl()); } }
应用举例
ArrayList.remove(Object o)
查看 ArrayList.remove(Object o) 源码:
@Override public boolean remove(Object object) { Object[] a = array; int s = size; if (object != null ) { for ( int i = 0 ; i < s; i++) { if (object.equals(a[i])) { System.arraycopy(a, i + 1 , a, i, --s - i); a[s] = null ; size = s; modCount++; return true ; } } } else { for ( int i = 0 ; i < s; i++) { if (a[i] == null ) { System.arraycopy(a, i + 1 , a, i, --s - i); a[s] = null ; size = s; modCount++; return true ; } } } return false ; }
如上,在遍历寻找过程中,是通过equals()来判断相等的,所以如果 object 是自定义类型,如果不重写 equals() 方法,则删除是同一个(即内存地址相同)的对象;如果要实现删除内存地址不同而只是内容相同(判断是否相同的标准在 equals()方法中定义)的对象,则一定要重写 equals()方法,否则将会出现误删或内容明明相同却无法删除的情况。
而且,在使用ArrayList.remove(Object o)时不必再进行遍历,直接调用就行。即要么是:
<pre name= "code" class = "java" > for ( int i = 0 ; i < list.isze(); i++) { if (list.get(i).id == obj.id) { list.remove(i); break ; } }
要么:
而不要多此一举,因为如上所示 jdk 源码里已经做了遍历:
<pre name= "code" class = "java" > for ( int i = 0 ; i < list.isze(); i++) { if (list.get(i).id == obj.id) { list.remove(obj); break ; } }
ArrayList.contains(Object o)
除此之外,contains方法也是通过equals实现的,以ArrayList为例,具体源代码如下:
public boolean contains(Object o) { return indexOf(o) >= 0 ; } 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 ; }
所以,当contains()的参数是自定义类而且内容相同、内存地址不同仍视为“相同”时,必须重写该类的equals()。