Object 是 Java 的基类,它的大部分方法都是 native 修饰的,标记方法是 Java 中的本地方法,一般是用 C/C++ 语言实现的。下面我们就来分析一下这个类。
registerNatives 方法将 C/C++ 种的方法映射到 Java 中的 native 方法,实现方法命名的解藕。此函数在类的静态代码块中,在类首次加载时执行。
private static native void registerNatives(); | |
static { | |
registerNatives(); | |
} |
在 JDK1.8 以及之前,Object 的构造方法是没有写出来的,但是编辑器默认其有一个无参构造方法。从 JDK1.9 之后,Object 的构造方法被显示写出。@HotSpotIntrinsicCandidate 注解是特定于 Java 虚拟机的注解。
@HotSpotIntrinsicCandidate | |
public Object() {} |
getClass 方法返回对象运行时的类,即返回的是动态类型的类。如果这个类被另一个
@HotSpotIntrinsicCandidate | |
public final native Class<?> getClass(); |
Java 不是存粹的静态类型或者动态类型,A a,A 就是静态类型,若 B 继承于 A,a = new B (),B 就是动态类型。
可以通过以下例子看出 getClass 方法的返回。
A a = new A(); | |
A b = new B(); | |
B c = new B(); | |
System.out.println(a.getClass().getName()); | |
System.out.println(b.getClass().getName()); | |
System.out.println(c.getClass().getName()); |
运行结果:
test.A
test.B
test.B
hashCode 方法返回对象的哈希值,它的存在是为了提高 HashTable、HashMap 等的效率。对于同一对象,在不改变 equals 方法前提下,必须返回相同的哈希值。对于 equals 方法返回 true 的两个对象,哈希值必须返回相同的。对于 equals 方法返回 false 的两个对象,哈希值可以相同也可以不相同,但是我们应该尽量让他们的哈希值不相同。
HotSpotIntrinsicCandidate | |
public native int hashCode(); |
equals 方法比较两个对象的相等性,此处比较的是两个对象的地址。
public boolean equals(Object obj) { | |
return (this == obj); | |
} |
clone 方法返回一个对象的复制。使用克隆方法的类必须实现 Cloneable 接口,否则会抛出 CloneNotSupportedException 异常。
@HotSpotIntrinsicCandidate | |
protected native Object clone() throws CloneNotSupportedException; |
toString 方法返回对象的字符串。如果我们自己的类没有重写 toString 方法,就会返回类名加类的哈希值的 16 进制的表示。
public String toString() { | |
return getClass().getName() + "@" + Integer.toHexString(hashCode()); | |
} |
notify 方法唤醒正在此对象上等待的一个线程,如果有多个线程在等待,则由 JVM 决定选择其中一个唤醒。
@HotSpotIntrinsicCandidate | |
public final native void notify(); |
notifyAll 方法唤醒全部等待的线程。
@HotSpotIntrinsicCandidate | |
public final native void notifyAll(); |
wait 方法使一个线程进入等待状态,直到其他线程调用 notify 或 notifyAll 方法或等待时间到达指定时间。当指定时间为 0 时,只能等待其他线程唤醒。
public final void wait() throws InterruptedException { | |
wait(0L); | |
} | |
public final native void wait(long timeoutMillis) throws InterruptedException; | |
public final void wait(long timeoutMillis, int nanos) throws InterruptedException { | |
if (timeoutMillis < 0) { | |
throw new IllegalArgumentException("timeoutMillis value is negative"); | |
} | |
if (nanos < 0 || nanos > 999999) { | |
throw new IllegalArgumentException( | |
"nanosecond timeout value out of range"); | |
} | |
if (nanos > 0) { | |
timeoutMillis++; | |
} | |
wait(timeoutMillis); | |
} |
调用对象的 wait ()、notify ()、notifyAll () 方法之前必须获得对象的锁,否则会出现 java.lang.IllegalMonitorStateException 异常。对象执行 wait () 方法之后,线程释放锁进入等待状态,直到其他线程将其唤醒或该线程被中断或线程等待时间达到指定长度。当线程被唤醒之后,并不能立马获得对象的锁,而是重新竞争锁,线程必须拿到锁之后才能继续执行。另一个线程执行了 notify () 或 notifyAll () 方法之后也不会立马释放锁,要执行完 synchronized 语句块才会释放锁。当其他线程执行了 notify () 方法之后,JVM 会从等待该锁的线程中选择一个唤醒,执行了 notifyAll () 方法之后,会唤醒全部等待该锁的线程。
public static void main(String[] args) { | |
ObjectTest objectTest = new ObjectTest(); | |
Test test = new Test(); | |
Thread thread1 = new Thread(() -> { | |
synchronized (objectTest) { | |
try { | |
System.out.println("1"); | |
objectTest.wait(); | |
System.out.println("2"); | |
} catch (InterruptedException e) { | |
e.printStackTrace(); | |
} | |
} | |
}); | |
thread1.start(); | |
Thread thread3 = new Thread(() -> { | |
synchronized (test) { | |
try { | |
System.out.println("3"); | |
test.wait(); | |
System.out.println("4"); | |
} catch (InterruptedException e) { | |
e.printStackTrace(); | |
} | |
} | |
}); | |
thread3.start(); | |
Thread thread2 = new Thread(() -> { | |
synchronized (objectTest) { | |
System.out.println("5"); | |
objectTest.notify(); | |
System.out.println("6"); | |
} | |
}); | |
thread2.start(); | |
} |
输出结果如下,并且主线程并没有停止,处于等待状态。
1
3
5
6
2
当垃圾回收器认为一个对象没有其他引用时,就调用 finalize () 方法清理对象。
@Deprecated(since="9") | |
protected void finalize() throws Throwable { } |