java里的==和equals,int和Integer的相等判断
1、“==表示比较地址,equals表示比较属性”这句话是错的
论证为什么是错的,思考一个问题:int a = 1; int b = 1; a == b 是true还是false?按照上面话,比较的是地址,自然是false了,但实际情况却是true,可以得出上面前半句是错误的
代码
int a = 1;
int b = 1;
System.out.println("a==b -> " + (a==b));
结果
a==b ->true
2、==表示真正的意思是什么
从概念方面来说:
- 基本数据类型:变量名指向具体的数值
- 引用类型:变量名指向存储数据的内存地址,即变量名指向hash值
从内存构建方面来说:
- 基本数据类型:变量声明了,jvm就会立刻给它分内存空间
- 引用类型:声明时,不会立刻分配内存,而是存储了一个内存地址,指向内存中的对象,内存中的对象有三部分组成:对象头+实例数据+对齐数据
当基本数据类型使用 == 比较时,由于变量名指向的是具体的数值,比较的是值是否相等,而应用类型使用 == 比较时,由于变量名指向的是内存地址,拿两个地址来比较,这样就造成了 == 是比较地址的错误。
3、equals方法是针对引用类型比较的,基本数据类型没有equals方法
equals方法是针对引用类型比较的,基本数据类型没有equals方法,来自于所有类的祖先Object类,判断成员变量是否相等使用equals方法,equals方法需要重写用来比较每个成员变量是否相等。
4、“重写equals方法就需要重写hashCode方法”也是错误的
既然重写了equals方法,就可以判断成员变量是否相等,为什么要重写hashCode方法呢,这里就涉及到HashMap、HashSet的应用了,这里拿HashMap举例,我们都知道HashMap是不重复的数据结构,采用Key-value的方式,通过判断Key值是否相等来决定是否添加元素,这里就涉及到Key的比较问题了,这里又引出一个问题,即使Key是如何比较的
Key的比较问题
- 首先比较的是hashCode
- 其次比较的是成员变量
源码:
public boolean containsKey(Object key) {
return getNode(hash(key), key) != null;
}
final Node<K,V> getNode(int hash, Object key) {
Node<K,V>[] tab; Node<K,V> first, e; int n; K k;
if ((tab = table) != null && (n = tab.length) > 0 &&
(first = tab[(n - 1) & hash]) != null) {
if (first.hash == hash && // always check first node
((k = first.key) == key || (key != null && key.equals(k))))
return first;
if ((e = first.next) != null) {
if (first instanceof TreeNode)
return ((TreeNode<K,V>)first).getTreeNode(hash, key);
do {
if (e.hash == hash &&
((k = e.key) == key || (key != null && key.equals(k))))
return e;
} while ((e = e.next) != null);
}
}
return null;
}
static final int hash(Object key) {
int h;
return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
}
可以看到先比较了hashCode,使用了equals比较成员变量
综上所述,得出结果:重写equals方法和重写hashCode方法没有半毛钱关系