Java把现实中的任何事物都当做一个对象(Object),Java是面向对象的,就是Object-Oriented简称OO
Object在Java中被定义为一个顶级父类,它是任何类的父类,我们可以显示的继承它,也可以隐式继承
Object类中定义的常用方法
equals(Object obj)
equals()
方法与==
的区别:
==
比较的是两个引用的值,即两个对象的地址。两次创建的对象是相互对立的,都各自分配了独立的内存空间,所有str1 != str2
equals()
比较的是两个引用指向的对象的实际的值,涉及到对象的属性和方法。上例中两个对象的值都为Hello
,所以str1.equals(str2)
由于Java中String类型是不可变的,也就是说在创建了一个字符串之后,如果想修改这个字符串的值是不能直接在原来的内存中修改存储的,而是需要重新分配一个内存空间用来存放新的内存空间。
String类的这种特性造成在对String对象进行创建或操作时非常浪费内存空间,为了解决这个问题,Java中引出一个字符串池的概念(a pool of String)。即:如果当前准备新创建的字符串对象的值在复用池中已经存在,那么就不在生成新的对象,而是复用池中已有的字符串对象,新建的字符串和原来同值的字符串内存地址是相同的。
注意的是,这种字符串池的机制只有采用Object obj ="Hello"
方式(而非用new
关键字)声明String对象的时候才有效。
hashCode()
Object类中定义了hashCode()
方法决定了所有的对象都可以调用其hashCode()方法。
在HashMap的存储实现中,系统会根据对象的hashCode()值来决定每个元素的存储位置。
这个时候会有一个疑问,就是会不会出现两个对象的hashCode()值相同呢?
- 对象相等则hashCode()一定相等;
- hashCode()相等对象未必相等。
hashCode()
存储机制中,不同的hashCode()值的对象会被分配到不同的“桶”里面,hashCode()值相同的对象会被放进同一个“桶”里面。在查询的过程中,一般是先遍历所有的桶再遍历桶里面的元素,所以为了能有一个高效的查询效果,我们应该尽可能的让所有的对象都被分配的自己独有的“桶”里面,这样才能最快的实现查询,要实现这样的要求就需要这些对象的hashCode()值不相同。
hashCode()
、equals()
和==
三者的关系
- 如果是基本变量,没有
hashCode()
和equals()
方法,基本变量的比较方式就只有==
。因为他们不是对象,当然是可以通过Java中的包装类将他们转换成对象后还是可以调用hashCode()
和equals()()
方法。 - 如果是变量,由于在Java中所有变量定义都是一个指向实际存储的一个句柄(你可以理解为c++中的指针),
==
是比较句柄的地址(你可以理解为指针的存储地址),而不是句柄指向的实际内存中的内容,- 如果要比较实际内存中的内容,那就要用
equals()
方法, - 但是如果是我们自己定义的一个类,比较自定义类用
equals()
和==
是一样的,都是比较句柄地址,因为自定义的类是继承于Object
,而Object
中的equals()
就是用==
来实现的,所以在自定义类的情况下重写equals()方法会是一个良好的习惯,否则失去了equals()方法存在的意义了。 - 那为什么我们用的String等等类型
equals()
是比较实际内容呢,是因为String
等常用类已经重写了Object
中的equals()
方法,让equals()
来比较实际内容。
hashCode()
在一般的应用中我们不需要了解hashCode()
的用法,但当我们用到HashMap
,hashset
等集合类时要注意下hashCode()
。我们想通过一个Object
的key
来拿HashMap
的value
,HashMap
的工作方法是,通过你传入的Object
的hashCode()
在内存中找地址,当找到这个地址后再通过equals()()
方法来比较这个地址中的内容是否和你原来放进去的一样,一样就取出value。- 所以这里要匹配2部分,
hashCode()
和equals()
。但假如说我们new
一个Object
作为key
去拿value
是永远得不到结果的,因为每次new
一个Object
,这个Object
的hashCode()
是永远不同的,所以我们要重写hashCode()
,你可以令你的hashCode()
是Object
中的一个恒量,这样永远可以通过你的Object
的hashCode()
来找到key的地址,然后你要重写你的equals()
方法,使内存中的内容也相等
首先,从语法角度,也就是从强制性的角度来说,hashCode()
和equals()
是两个独立的,互不隶属,互不依赖的方法,equals()
成立与hashCode()
相等这两个命题之间,谁也不是谁的充分条件或者必要条件。
但是,从为了让我们的程序正常运行的角度,我们一定要(正确)重载hashCode()
,使得equals()
成立的时候,hashCode()
相等,也就是
a.equals(b) -> a.hashCode()== b.hashCode()
总结一下,equals()
是对象相等性比较,hashCode()
是计算对象的散列值,当然他们的依据是对象的属性。
对于equals()
,一般我们认为两个对象同类型并且所有属性相等的时候才是相等的,在类中必须改写equals()
,因为Object
类中的equals()
只是判断两个引用变量是否引用同一对象,如果不是引用同一对象,即使两个对象的内容完全相同,也会返回false。当然,在类中改写这个equals()
时,你也可以只对部分属性进行比较,只要这些属性相同就认为对象是相等的。
对于hashCode()
,只要是用在和哈希运算有关的地方,和equals()
一样,在你的类中也应该改写。当然如果两个对象是完全相同的,那么他们的`hashCode()当然也是一样的,但是象前面所述,规则可以由你自己来定义,因此两者之间并没有什么必然的联系。
当然,大多数情况下我们还是根据所有的属性来计算hashCode()
和进行相等性比较。
Reference
http://blog.chinaunix.net/uid-26981819-id-4462638.html
http://www.cnblogs.com/I-am-Betty/archive/2010/09/06/1819375.html