Java Object类详解

我们都知道:在Java中,所有的类都继承了Object这个基类,并且大家都知道,Object有几个比较通用的方法,如equals(),clone(),toString(),我们需要在使用它们的时候进行覆写,今天,我们就具体的探究下这几个方法。

void registerNatives()

这是个Native方法,在静态块中调用,其目的是将hashCode,wait,notify,notifyAll和clone方法注册到本地。

Class<?> getClass()

同样是个Native方法,获取对象的Class。

int hashCode()

Native方法,生成哈希码,其中注意三点

  • 一个对象在同一个进程被多次调用,但是它的哈希码仍然应该是相同的。但是,当同一个对象在不同进程中执行,则哈希码有可能不同。JavaDoc原文如下

    Whenever it is invoked on the same object more than once during an execution of a Java application, the {@code hashCode} method must consistently return the same integer, provided no information used in {@code equals} comparisons on the object is modified. This integer need not remain consistent from one execution of an application to another execution of the same application.

  • 如果两个对象通过equals()比较返回true,那么它们的哈希码应该相同。

  • 如果两个对象通过equals()比较返回false,那么它们的哈希码应该不同。

boolean equals(Object obj)

这恐怕使我们最常用的方法之一了,我们在实际应用中,也经常遇到什么时候用equals(),什么时候用==的问题。一般来说,基本数据类型用==,因为这样可以直接比较它们的值,但是复合数据类型如果我们用==的话,那么实际上我们比较的就是它们的引用了,除非它们指向的是同一个对象,否则它们不可能相等,因此我们比较符合数据类型一般用equals(),并且我们应该覆写equals(),这是因为Object的equals()方法默认的也是用==进行判定:

public boolean equals(Object obj) {
        return (this == obj);
    }

我们再来看看我们经常用的String是如何覆写equals()方法的:

public boolean equals(Object anObject) {
    if (this == anObject) {
        return true;
    }
    if (anObject instanceof String) {
        String anotherString = (String)anObject;
        int n = value.length;
        if (n == anotherString.value.length) {
            char v1[] = value;
            char v2[] = anotherString.value;
            int i = 0;
            while (n-- != 0) {
                if (v1[i] != v2[i])
                    return false;
                i++;
            }
            return true;
        }
    }
    return false;
}

在这里还有一个很有趣的问题,请看下面的例子

String s1 = "String";
String s2 = "String";

System.out.println("The result is " + s1.equals(s2));

你会发现返回值为True,这个就和我们上面讲的不一样了,按照我们上面的讲解,这时候应该返回false才对。其实是这样的,因为JVM中会维护一个字符串池,如果池中已经有包含此对象的字符串的时候,那么它就会返回池中的字符串(当然如果你new一个新的String对象的话就另当别论。)所以这个时候返回的是true。

Object clone()

Native方法,我们一般用它来复制一个对象,并且用clone()可以实现深复制(将所有需要复制的对象都复制了一遍,而不单单是用引用指向原来的对象。)示例如下:

public class Animal implements Cloneable {
    private int height;
    private int age;

    public Animal(int height, int age){
        this.height = height;
        this.age = age;
    }

    @Override
    public Object clone() throws CloneNotSupportedException {
        return super.clone();
    }

    @Override
    public String toString() {
        return "Animal{" +
                "height=" + height +
                ", age=" + age +
                '}';
    }

    public int getHeight() {
        return height;
    }

    public void setHeight(int height) {
        this.height = height;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }
}


public class People implements Cloneable {

    private int height;
    private int age;
    private Animal a;


    public People(int height, int age,Animal a){
        this.height = height;
        this.age = age;
        this.a = a;
    }

    @Override
    public Object clone() throws CloneNotSupportedException {
        People p = (People) super.clone();
        p.a = (Animal) a.clone();
        return p;
    }

    @Override
    public String toString() {
        return "People{" +
                "height=" + height +
                ", age=" + age +
                ", a=" + a +
                '}';
    }

    public int getHeight() {
        return height;
    }

    public void setHeight(int height) {
        this.height = height;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }


    public void setAnimalAge(int a) {
        this.a.setAge(5);
    }
}

接下来我们这样调用:

Animal a1 = new Animal(100,3);
People p1 = new People(173,24,a1);

People p2 = (People) p1.clone();
p2.setAge(26);
p2.setHeight(181);
p2.setAnimalAge(6);

System.out.println(p1.toString());
System.out.println(p2.toString());

这样我们就完成深复制了。

String toString()

最常用的方法,我们一般用它获取对象成员变量的值。Object的默认实现:

public String toString() {
    return getClass().getName() + "@" + Integer.toHexString(hashCode());
}

void notify(),void notifyAll()

Native方法,多线程时应用,通知其他线程等待结束。

void wait(long),void wait(long,int),void wait()

Native方法,通知线程等待。

void finalize()

垃圾回收。当JVM判断一个对象可以被垃圾回收时,那么JVM会调用finalize()方法,但是记住,它只能调用一次(所以如果你想这个对象不被垃圾清除的话,你就要在这里面做点事情了),但是一般你不能依赖在这里做垃圾回收的工作,在《Java编程思想》中说明了有关finalize()的一个用法,那就是通过finalize()来进行对象终结对象的判断。