Java中的Object对象

2016/4/14 posted in  Java

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()的用法,但当我们用到HashMaphashset等集合类时要注意下hashCode()。我们想通过一个Objectkey来拿HashMapvalueHashMap的工作方法是,通过你传入的ObjecthashCode()在内存中找地址,当找到这个地址后再通过equals()()方法来比较这个地址中的内容是否和你原来放进去的一样,一样就取出value
  • 所以这里要匹配2部分,hashCode()equals()。但假如说我们new一个Object作为key去拿value是永远得不到结果的,因为每次new一个Object,这个ObjecthashCode()是永远不同的,所以我们要重写hashCode(),你可以令你的hashCode()Object中的一个恒量,这样永远可以通过你的ObjecthashCode()来找到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