Object类概述

在Java中,Object类是所有类的基类/超类,一个类如果没有明确继承的父类,那么该类就默认继承Object类。下面介绍一下Object类中的几个常用方法。

Object()

该方法是Object类的无参构造方法,该方法默认存在,但在JDK源码中我们看不到该方法的声明和具体实现。对于任何Java类,如果不显示的声明类的构造方法,则默认的会存在一个无参构造方法。

getClass()

public final native Class<?> getClass()

该方法返回当前对象所属的类对象,类型为Class。通常用于判断两个引用中实际存储对象类型是否相同。示例代码如下:

public class A {

}
A a1=new A();
A a2=new A();
Class<? extends A> b1=a1.getClass();
Class<? extends A> b2=a2.getClass();
System.out.println(b1==b2);
//输出:true

hashCode

public native int hashCode()

本地方法,由JVM负责实现。该方法用于返回一个整型数据,该整型数据代表了当前对象的哈希值。JDK中对Hash值的约定如下:

  • 相同的对象多次调用该方法时必须返回相同的值
  • 在不同的应用中调用该方法返回的哈希值不要求一定相同
  • 不同的对象返回的哈希值可以相同

如果子类没有重写equals方法,则对象的相同依据内存地址是否相同来判断。如果重写了equals方法,则依据equals方法来判断。为了保证哈希的约定,重写equals方法时也要重写hashCode方法。如果重写了equals方法,但没有重写hashCode方法,则会违反相同的对象具有相等的哈希值这一约定。示例代码如下:

public class A {

}
A a1=new A();
A a2=new A();
System.out.println(a1.hashCode());
System.out.println(a2.hashCode());
/*
输出:
360067785
1860250540
*/

equals(Object obj)

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

该方法用于实现比较两个对象是否相等,如果相等,则返回true,如果不相等,则返回false。JDK对该方法提供了默认实现,从源码可以看出,默认情况下对象的是否相等是通过“==”进行判断的。因此,也就意味着,JDK默认比较两个对象是否相等是通过比较两个对象的内存地址是否相同为判断依据。一般情况下,子类可能会重写equals()方法,以反映对象相等的真实语义。示例代码如下:

public class A {

}
A a1=new A();
A a2=new A();
//引用数据类型使用==是比较内存地址是否相等
System.out.println(a1==a2);
System.out.println(a1.equals(a2));
int a=10;
int b=20;
//基本数据类型使用==是比较数值是否相等
System.out.println(a==b);
/*
输出:
false
false
false
*/

clone()

protected native Object clone() throws CloneNotSupportedException;

该方法用于对象的克隆,返回对象的拷贝。如果此对象的类不能实现接口Cloneable,则会抛出CloneNotSupportedException。此方法执行的是该对象的“浅复制”。

toString()

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

toString()方法返回值为String类型,JDK对该方法提供了默认实现。依照JDK源码可知,该方法默认的返回“对象的类名@十六进制表示的对象哈希值”。一般情况下,toString()方法应当返回当前对象的“字符串表示”,返回值应该是人工可读的,且尽量能够表示对象本身。因此,JDK官方推荐子类重写该方法,使其返回有意义的字符串。示例代码如下:

public class A {
	public String toString() {
		return "我是A";
	}
}
A a1=new A();
System.out.println(a1);//打印对象,默认调用toString()
System.out.println(a1.toString());
/*
输出:
我是A
我是A
*/

notify()

public final native void notify();

唤醒在此对象监视器上等待的单个线程,如果有多个线程等待,则只会选择唤醒其中一个线程。该线程的选择是任意性的。线程通过调用其中一个wait方法,在对象的监视器上等待。直到当前的线程放弃此对象上的锁定,才能继续执行被唤醒的线程。被唤醒的线程将以常规方式与在该对象上主动同步的其他所有线程进行竞争。此方法只应由作为此对象监视器的所有者的线程来调用,一次只能有一个线程拥有对象的监视器。通过以下三种方法之一,线程可以成为此对象监视器的所有者:

  • 通过执行此对象的同步实例方法
  • 通过执行在此对象上进行同步的语句的正文
  • 对于Class类型的对象,可以通过执行该类的同步静态方法

notiyfAll()

public final native void notifyAll();

与notify()不同的是该方法唤醒在此对象监视器上等待的所有线程。

wait(long timeout)

public final native void wait(long timeout) throws InterruptedException;

导致当前的线程等待,直到其他线程调用此对象的notify方法或notifyAll方法,或者超过指定的时间量。当前的线程必须拥有此对象监视器。

finallize()

protected void finallize () throws Throwable {}

当垃圾回收器确定不存在对该对象的更多引用时,由对象的垃圾回收器调用此方法。子类重写finallize方法,以配置系统资源或执行其他清除。当JVM已确定尚未终止的任何线程无法再通过任何方法访问此对象时,将调用此方法,除非由于准备终止的其他某个对象或类的终结操作执行了某个操作。finallize方法可以采取任何操作,其中包括再次使此对象对其他线程可用;不过,finallize的主要目的是在不可撤销地丢弃对象之前执行清除操作。Java编程语言不保证哪个线程将调用某个给定对象的finallize方法。但可以保证在调用finallize时,调用finallize的线程将不会持有任何用户可见的同步锁定。如果finallize方法抛出未捕获的异常,那么该异常将被忽略,并且该对象的终结操作将终止。在启用某个对象的finallize方法后,将不会执行进一步操作,直到Java虚拟机再次确定尚未终止的任何线程无法再通过任何方法访问此对象,其中包括由准备终止的其他对象或类执行的可能操作,在执行该操作时,对象可能被丢弃。对于任何给定对象,Java虚拟机只调用一次finallize方法。