JDK源码阅读(1):Object类阅读笔记
Object
1. @HotSpotIntrinsicCandidate
@HotSpotIntrinsicCandidate
public final native Class<?> getClass();
使用@HotSpotIntrinsicCandidate
注解标注的方法,表示JVM可能为该方法提供了一些基于CPU指令的高效实现,而非使用Java的实现。
2. native方法
getClass()
、hashCode()
、clone()
、notify()
等方法的默认实现都是native方法
3. equals方法
equals()
方法默认实现
public boolean equals(Object obj) {
return (this == obj);
}
4. clone方法
clone()
方法默认是native实现,且默认是一个浅拷贝。但要调用这个方法,要求类实现Clonable
接口,否则会抛出CloneNotSupportedException
异常。即使Clonable
没有定义任何方法。
public interface Cloneable {
}
下面是一个简单的示例
public class Test implements Cloneable{
public int a = 10;
public static void main(String[] args) {
try {
Test test = new Test();
Object clone = test.clone();
System.out.println(clone.getClass());
System.out.println(test.getClass());
System.out.println(test.a);
Test toClone = (Test)clone;
System.out.println(toClone.a);
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
}
}
// 输出
class Test
class Test
10
10
6. toString方法
public String toString() {
return getClass().getName() + "@" + Integer.toHexString(hashCode());
}
默认实现返回类名+十六进制哈希码
7. notify和notifyAll方法
唤醒在对象监视器上等待的线程。
有下面这些方法令当前线程获得一个对象的监视器
- 执行synchronized方法
- 执行synchronized块
- 执行synchronized的静态方法(获得的是当前类的class对象的监视器)
8. wait方法
下面是一个带纳秒参数nano
的wait方法
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 < Long.MAX_VALUE) {
timeoutMillis++;
}
wait(timeoutMillis);
}
我们看到第三个if判断,假如nano参数大于0且timeoutMillis参数未满,所做的直接是令timeoutMillis参数自增。最后直接调用wait(timeoutMillis)
,这简直是对程序员的欺骗。注:1ms = 1000000ms
下面的这段代码是一段示例代码。推荐的等待方法是在调用wait的while循环中检查等待的条件,如下例所示。 这种方法避免了可能由虚假唤醒引起的问题。
虚假唤醒:线程可以在没有被通知、中断或超时的情况下唤醒
synchronized (obj) {
while (<condition does not hold> and <timeout not exceeded>) {
long timeoutMillis = ... ; // recompute timeout values
int nanos = ... ;
obj.wait(timeoutMillis, nanos);
}
... // Perform action appropriate to condition or timeout
}
9. finalize方法
@Deprecated(since="9")
protected void finalize() throws Throwable { }
显然我们看到,通过@Deprecated(since="9")
注解,标记了finalize()
方法自JDK9开始被弃用。
不推荐使用的原因
-
finalize()方法不能保证执行。
还有另外一个方法能够回收对象,Runtime.getRuntime().runFinalization(); 但是这只能保证GC做出最大的努力,但是我们也不能finalize方法都能执行。我们还有一种方式能够保证执行finalize()方法,Runtime.runFinalizersOnExit(true),这个方法已经被JDK弃用,因为这种方法本质上是不安全的,可能导致finalizers方法被活对象调用而其他线程正在并行操作这个对象,从而导致不正确的行为或者死锁。 -
finalize()方法不像构造方法在链中工作,意味着像当你调用构造方法的时候,超类中的构造方法也会被隐含的调用,但是在finalize()方法的这种情况中,这种隐含的调用不会发生。超类中的finalize()方法需要显示的调用。假设,你创建了一个类并且小心翼翼的写了finalize()方法。一些人来extend了你的类,但是在子类中的finalize()块中没有调用super.finalize()方法。然后超类中finalize()方法将永远都不会被调用。
-
任何有finalize()方法抛出的异常都会被GC线程忽略而且不会被进一步传播,事实上也不会在日志文件上记录下来。
正确的姿势
- 要在finalize()方法中一直调用super.finalize()。
- 考虑到不可预测预测性,不要在时间要求高的应用中使用finalize()。
- 不要使用Runtime.runFinalizersOnExit(true);方法,因为你可能将你的系统置于危险之中。
- 尝试遵循下边的模板使用finalize()方法。
@Override
protected void finalize() throws Throwable{
try{
//release resources here
}catch(Throwable t){
throw t;
}finally{
super.finalize();
}