摘要
大家都知道Object是所有类的父类,任何类都默认继承Object,因此省略了extends Object关键字。Objec类中的方法在任何一个java类中都可以使用,下面学习的类的顺序以jdk源码为准
Object类的常用方法:toString(),getClass(),hashCode(),equals(),clone(),finalize()
定义为final类型,不能重写的方法:getClass(),notify(),notifyAll(),wait()
1、registerNatives方法:
private static native void registerNatives();
static {
registerNatives();
}
registerNatives被native修饰为本地方法,这些方法不是由java语言编写,通常由C、C++语言编写。被static修饰为静态方法。而且在静态代码块中,Object类加载的时候会先执行registerNatives方法,registerNatives方法会进行一些跟系统有关的方法调用,而这个方法的实现就在java.dll中,里面会根据不同系统来执行不同的底层操作。
2、getClass方法:
public final native Class<?> getClass();
getClass被native修饰为本地方法,被final修饰子类不能够重写此方法,返回值采用泛型,返回Object的运行时类类型,一般和getName()联合使用,如getClass().getName()。通过该方法或以获取类的元数据和方法信息。它能够获取一个类的定义信息,然后使用反射去访问类的全部信息,包括函数和字段。
3、hashCode方法:
public native int hashCode();
hashCode被native修饰为本地方法,该方法返回该对象的哈希码值,hashCode方法在一些具有哈希功能的Collection中用到。用于哈希查找,可以减少在查找中使用equals的次数,重写了equals方法一般都要重写hashCode方法。
根据官方文档的定义,整理以下关键点:
- hashCode的存在主要是用于查找的快捷性,如Hashtable,HashMap等,hashCode是用来在散列存储结构中确定对象的存储地址的;
- 如果两个对象相同,就是满足于equals(Java.lang.Object) 方法,那么这两个对象的hashCode一定要相同;
- 如果对象的equals方法被重写,那么对象的hashCode也尽量重写,并且产生hashCode使用的对象,一定要和equals方法中使用的一致,否则就会违反上面第2点;
- 两个对象的hashCode相同,并不一定表示两个对象就相同,也就是不一定适用于equals(java.lang.Object) 方法,只能够说明这两个对象在散列存储结构中,如Hashtable,他们“存放在同一个篮子里”。
深入理解hashcode和hash算法请移步于:https://blog.youkuaiyun.com/qq_38182963/article/details/78940047
4、equals方法:
public boolean equals(Object obj) {
return (this == obj);
}
equals直接判断this和obj本身的值是否相等,即用来判断调用equals的对象和形参obj所引用的对象是否是同一对象。这里的==比较的是对象的引用,也就是"地址值",如果this和obj指向的是同一块内存对象,则返回true,如果this和obj指向的不是同一块内存,则返回false。如果希望不同内存但相同内容的两个对象equals时返回true,则我们需要重写父类的equal方法,String类已经重写了object中的equals方法,比较内容是否相等。
5、clone方法:
protected native Object clone() throws CloneNotSupportedException;
clone被native修饰为本地方法,protected保护方法,实现对象的浅复制,只有实现了Cloneable接口才可以调用该方法,否则抛出CloneNotSupportedException异常。
6、toString方法:
public String toString() {
return getClass().getName() + "@" + Integer.toHexString(hashCode());
}
toString方法返回一个字符串,类名+@+哈希值的16进制无符号整数形式。该方法用得比较多,一般子类都有覆盖。
public class Test1 {
public static void main(String[] args){
Object o1 = new Object();
System.out.println(o1.toString());
}
}
//输出:java.lang.Object@7852e922
7、notify方法:
public final native void notify();
notify被native修饰为本地方法,不可被重写,该方法唤醒在该对象上等待的某个线程。
8、notifyAll方法:
public final native void notifyAll();
notifyAll被native修饰为本地方法,不可被重写,该方法唤醒在该对象上等待的所有线程。
9、wait(long timeout)方法:
public final native void wait(long timeout) throws InterruptedException;
wait被native修饰为本地方法,不可被重写,调用该方法后当前线程进入睡眠状态,让当前线程等待,使线程等待指定长的时间(毫秒)。在其他线程调用了notify或是notifyAll方法或是达到指定的时长,该线程就可以被调度。其他线程调用了interrupt中断该线程,就抛出一个InterruptedException异常。
10、wait(long timeout, int nanos)方法:
public final void wait(long timeout, int nanos) throws InterruptedException {
if (timeout < 0) {
throw new IllegalArgumentException("timeout value is negative");
}
if (nanos < 0 || nanos > 999999) {
throw new IllegalArgumentException(
"nanosecond timeout value out of range");
}
if (nanos >= 500000 || (nanos != 0 && timeout == 0)) {
timeout++;
}
wait(timeout);
}
wait不可被重写,和wait(long timeout)方法本质相同,允许更好地控制在放弃之前等待通知的时间,实时量,以毫微秒计算,计算公式如下:1000000*timeout+nanos,特别是wait(0, 0) 表示和wait(0)相同,当前线程必须拥有该对象的监视器。
三种异常:
- IllegalArgumentException – 如果超时的值是负的或毫微秒的值不在0-999999范围内。
- IllegalMonitorStateException – 如果当前线程不是对象监视器的拥有者。
- InterruptedException – 如果另一个线程中断了当前线程。当这种异常被抛出当前线程的中断状态被清除。
11、wait方法:
public final void wait() throws InterruptedException {
wait(0);
}
实际上调用的是wait(long timeout)方法只不过timeout传的是0,只有调用了notify或是notifyAll方法,线程才会被唤醒。
12、finalize方法:
protected void finalize() throws Throwable { }
该方法是protected方法,子类可以覆盖该方法以实现资源清理工作,GC在回收对象之前调用该方法。该方法与C++中的析构函数不是对应的。C++中的析构函数调用的时机是确定的(对象离开作用域或delete掉),但Java中的finalize的调用具有不确定性。
finalize的执行周期:当对象变成(GC Roots)不可达时,GC会判断该对象是否覆盖了finalize方法,若未覆盖,则直接将其回收。否则,若对象未执行过finalize方法,将其放入F-Queue队列,由一低优先级线程执行该队列中对象的finalize方法。执行finalize方法完毕后,GC会再次判断该对象是否可达,若不可达,则进行回收,否则,对象“复活”。