在Java中,Object类是所以类的子类,之所以要讲解下这个类,最主要的原因是里面涉及到的几个方法。

    一:equals方法

        定义:

public boolean equals(Object o) {} ;

    该方法起到的作用是比较两个对象是否“相等”。在Obejct类中已经实现了该方法,但该方法的默认逻辑等于比较两个对象的地址是否一样,即比较两个对象的引用是否是一样的。那么在何种情况下我们需要覆盖该方法呢?如果我们是要比较两个对象是否“逻辑相等”,那么我们就有必要覆写该方法。什么叫逻辑相等,例如我们规定:如果两个篮球的牌子,颜色,花纹是一样的那么两个篮球就“相等”。那么对于两个具体的篮球,他们是两个不同的对象,他们的引用地址肯定也是不一样的,但是如果满足我们“相等”的条件,那么我们也认为两个球是相等的,即满足前面的规定。

    那么在子类中覆写该方法应该注意些什么呢?下面做下简要的总结(假设有x,y,z三个对象,这三个对象的引用都不为null):

    1,对于一个对象来说,x.equals(x)必须返回为true。

         最直接的处理方式就是用“==”符号来比较他们引用的地址是否相等。

    2,对于两个对象来说,x.equals(y) 和 y.equals(x)的返回值必须相同

    3,对于三个对象来说,如果x.equals(y)返回为true,y.equals(z)返回也为true,那么x.equals(z)返回也必须为true。

    4,x.equals(null)返回必须为false .

    

    注意:在java的集合类都依赖于传递个他们的对象是否遵守了equals约定。例如判断一个集合对象中是否已经包含了某个对象的操作。

    

    那么我们怎么具体的实现该方法呢?总结如下:

    1,用"=="操作符检查传递进来的参数和当前的对象是否为同样的引用,如果是则返回为true,否则进入下面一步。

    2,使用"instanceof"操作符检查传递进来的参数是否为要比较的正确的类型,如果不是则返回false,否则下一步。一般来说,所谓正确的类型是指equals方法所在的那个类。

    3,把参数转换为正确的类型。因为参数是Object类型,所以先转换为正确的类型。

    4,对于该类中每个关键域(即用来判断两个对象是否相同的那么属性等),检查参数中的相应域是否匹配,如果全部匹配成功则返回为true,否则返回为false .

    --对于不是float,double的基本类型,可以使用==直接比较。

    --对于引用类型,可以递归的调用equals方法。

    --对于float类型,可以使用Float.compare方法

        因为存在Float.NaN、-0.0f这样的常量,所以和其他基本类型不同,需要单独做这样的处理。

    --对于double类型,可以使用Double.compare方法

        原因类同上面的float.

    --对于数组,则需要把上面的这些原则应用到每个元素上。如果要比较数组中的每个元素,还可以使用Arrays.equals方法。

    --对象引用域可能存在null的合法情况,为了避免空指针异常,则应该使用下面的习惯用法来比较这样的域。

    (field==null?o.field==null:field.equals(o.field))

    还可以这样:

    (field==o.field || (field==null?o.field==null:field.equals(o.field)))

    注意:在我们覆写equals方法的时候,我们应该同时覆写hashCode方法。因为Object规范规定,相等的对象必须具有相等的散列码。

    二:hashCode方法

    定义:

public int hashCode() ;

     为什么要实现该方法,其实就是为了让类能够结合所有的基于散列的集合一起正常的运作,例如:HashMap,HashSet和HashTable。对该方法我们应该知道:

    1,在应用程序执行期间,只要equals方法所用到的信息没被修改,那么对这同一个对象调用多次,hashCode方法必须始终如一地返回同一个整数。当然,当应用程序多次执行的过程中,每次返回的整数可以不同,只是每次应用程序执行,执行期间多次调用返回值必须一致。

    2,只要两个对象通过equals方法比较相等,那么两个对象的hashCode方法返回必须一致。

    3,如果两个对象通过equal方法比较不相等,那么两个对象的hashCode方法返回值可以不同。只是这个时候应该返回不同的指来提高散列表的性能。

    那么我们怎么覆些该方法比较好呢,下面给出一个方法:

    1,定义一个变量并赋值为一个非零的值,例如:int result = 17

    2,对于对象中的每个关键域(即equals方法中涉及的每个域),完成以下的步骤:

        a:如果为boolean类型,则计算(f?1:0) ;

        b:如果为byte,char,short或者int类型,则计算(int)f ;

        c:如果为long类型,则计算(int)(f^(f>>>32))

        d:如果为float类型,则计算Float.floatToIntBits(f)

        e:如果为double类型,则计算Double.doubleToLongBits(f),并得到值v,然后为得到的long类型的指计算(int)(v^(v>>>32))

        f:如果是引用类型,则调用该类型的hashCode方法。如果为null则返回0

        g:如果是数组,则对要使用的元素使用上面的算法,如果要计算数组中的每个元素则可以使用Arrays.hashCode方法。

    3,然后按照下面的方式,把上一个步骤计算得到的值c合并到result中:    

result = 31*result + c ;

    4,处理完每个关键域后,返回result。

    三:toString方法     

    定义:

pubic String toString(){}

    该方法的覆写更多是为了我们输入日志信息,把我们的关心的字段信息都输出来。所以可根据自己的需要来实现。

    四:clone方法

    注:谨慎的覆写该方法。

    该方法比较的特别,因为他在Object类中被声明为受保护的访问。而要使用该方法,我们必须让类实现Cloneable接口,该接口中不包含任何的方法,该接口只是为了决定Object中受保护的clone方法的实现行为,即如果一个类实现了Cloneable接口,那么Object的clone方法就返回该对象的逐域拷贝。当然,这种方法其实是不值得提倡的,因为通常情况下,实现一个接口是为了表明类可以为他的客户端做些什么,然后对于该接口,它却改变了超类中受保护的方法的行为。

    我们可以用另外的方法来实现对对象的拷贝,该方法是提供一个拷贝构造器或拷贝工厂。拷贝构造器只是一个构造器,它唯一的参数类型是包含该构造器的类,例如:

pubic X(X x) ;

    而拷贝工厂类似于拷贝构造器的静态工厂:

public static X newInstance(X x) ;

给个深度拷贝的例子:

public Object clone() {

//将对象写到流里    

ByteArrayOutputStream bytout=new ByteArrayOutputStream();    

ObjectOutputStream objos = null ;

ObjectInputStream objis = null ;

try {

objos = new ObjectOutputStream(bytout);

objos.writeObject(this);  

//从流里读出来    

ByteArrayInputStream bi=new ByteArrayInputStream(bytout.toByteArray());    

objis =new ObjectInputStream(bi); 

Object o = objis.readObject() ;

return o ;

} catch (IOException e1) {

e1.printStackTrace();

} catch (ClassNotFoundException e) {

e.printStackTrace();

}finally{

if(objos != null){

try {

objos.close();

} catch (IOException e) {

e.printStackTrace();

}

if(objis != null){

try {

objis.close();

} catch (IOException e) {

e.printStackTrace();

}

}

}    

return null ;

}

注意:用该方法对象应该实现Cloneable,Serializable接口

    五:compareTo方法

        其实该方法并没有在Object对象中声明,之所以放在这里,是因为该方法很有用。

        该方法是Comparable接口中唯一的方法。该接口主要是为了执行顺序的比较,该方法与equals方法有相似的特征,即equals方法判定对象相等时,该方法应该返回0。如果某个对象实现了来接口,那么我们可以通过下面的方式对对象数组排序。

Arrays.sort(a)

    Comparable接口定义如下:

pubic interface Comparable<T> {

        int compareTo(T t) ;

}

compareTo方法的通用约定如下:

    如果该对象(compareTo()方法所在的对象)与指定的对象对象进行比较,当该对象小于,等于或者大于指定对象的时候,分别返回一个负整数,零和正整数。如果由于指定对象的类型而无法与该对象进行比较,则抛出ClassCastException异常。

        

小结:对于这里所讲到的方法,最值得大家注意的就是equals和hashCode方法,其他的方法都可以根据需要来选择实现。然后对于java的集合,有下面两点值得注意:

    1,HashSet类型是利用hashCode和equals方法来去重复的

    2,SortedSet类型是通过compareTo来去重和排序
    3,Map类型是利用hashCode和equals方法来去重复的
    4,SortedMap类型是通过compareTo来去重和排序