Java中Object原理用法示例中文源码详解
原理机制
Object
类的原理主要包括以下几个方面:
-
根类:
Object
类是Java中所有其他类的根类。每个类都直接或间接地继承自Object
类。这意味着所有对象都具有Object
类的方法和属性。 -
默认实现:
Object
类提供了默认的方法实现,例如equals()
、hashCode()
、toString()
等。这些方法的默认实现通常基于对象的引用比较和哈希码生成规则,可以根据需要在子类中进行覆盖。 -
对象标识:
Object
类定义了equals()
和hashCode()
方法来处理对象的标识。equals()
方法用于判断两个对象是否相等,hashCode()
方法用于获取对象的哈希码。默认情况下,equals()
方法使用引用比较,而hashCode()
方法返回对象的内存地址的哈希码。 -
字符串表示:
Object
类的toString()
方法用于获取对象的字符串表示。默认情况下,它返回一个包含类名和哈希码的字符串。toString()
方法通常被用于打印对象的信息或调试目的。可以在子类中重写toString()
方法以提供更有意义的字符串表示。 -
类信息:
Object
类提供了getClass()
方法来获取对象的运行时类信息。该方法返回一个Class
对象,其中包含了类的元数据,如类名、父类、接口等信息。 -
线程同步:
Object
类提供了wait()
、notify()
和notifyAll()
方法,用于线程之间的同步与通信。这些方法必须在同步代码块或同步方法中使用,以确保正确的线程同步。 -
垃圾回收:
Object
类的finalize()
方法是Java垃圾回收机制的一部分。该方法在垃圾收集器确定没有对该对象的更多引用时被调用。子类可以覆盖finalize()
方法,在对象被销毁之前执行一些清理操作。
通过继承Object
类,其他类可以获得上述特性和功能。Object
类的原理主要是为了提供通用的方法和行为,以满足大多数对象的基本需求。具体的类可以根据自身需求在这些方法中进行定制化的实现。
用法
-
finalize()
方法:finalize()
方法是Java垃圾回收机制的一部分,在垃圾收集器确定没有对该对象的更多引用时被调用。可以在子类中覆盖finalize()
方法,执行对象的清理操作。 -
notify()
、notifyAll()
和wait()
方法:这些方法用于线程间的同步与通信。notify()
方法用于唤醒在该对象上等待的一个线程。notifyAll()
方法用于唤醒在该对象上等待的所有线程。wait()
方法使当前线程进入等待状态,直到其他线程调用该对象的notify()
或notifyAll()
方法唤醒它。
-
getClass()
方法:getClass()
方法返回对象的运行时类。它返回一个Class
对象,包含有关类的信息,如类名、父类、接口等。 -
equals()
方法:equals()
方法用于比较两个对象是否相等。默认情况下,它使用对象的引用比较来判断对象是否相等。可以在具体的类中覆盖equals()
方法以自定义相等性逻辑。 -
hashCode()
方法:hashCode()
方法返回对象的哈希码。哈希码是一个整数,用于快速查找对象在哈希表等数据结构中的位置。默认情况下,hashCode()
方法返回对象的内存地址转换成的整数值。 -
toString()
方法:toString()
方法返回对象的字符串表示。默认情况下,它返回包含对象类名和对象哈希码的字符串。可以在具体的类中覆盖toString()
方法,以提供更有意义的字符串表示。 -
clone()
方法:clone()
方法用于创建并返回当前对象的一个副本。默认情况下,它执行的是浅拷贝,即复制对象的字段值。如果需要实现深拷贝,可以在具体的类中重写clone()
方法。
总结来说,Object
类提供了一系列基本的方法和功能,用于处理对象的比较、同步、通信和字符串表示等。其他类通过继承Object
类,获得了这些通用的方法和功能。根据具体的需求,可以在具体的类中对这些方法进行定制化的实现。
示例
以下是每种方法的详细完整代码示例,包括main()
方法来演示输出:
equals()
方法:
public class MyClass {
private int value;
public MyClass(int value) {
this.value = value;
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null || getClass() != obj.getClass()) {
return false;
}
MyClass other = (MyClass) obj;
return value == other.value;
}
public static void main(String[] args) {
MyClass obj1 = new MyClass(10);
MyClass obj2 = new MyClass(10);
MyClass obj3 = obj1;
System.out.println(obj1.equals(obj2)); // 输出:true
System.out.println(obj1.equals(obj3)); // 输出:true
}
}
hashCode()
方法:
import java.util.Objects;
public class MyClass {
private int value;
public MyClass(int value) {
this.value = value;
}
@Override
public int hashCode() {
return Objects.hashCode(value);
}
public static void main(String[] args) {
MyClass obj = new MyClass(10);
System.out.println(obj.hashCode()); // 输出:10
}
}
toString()
方法:
public class MyClass {
private int value;
public MyClass(int value) {
this.value = value;
}
@Override
public String toString() {
return "MyClass{" +
"value=" + value +
'}';
}
public static void main(String[] args) {
MyClass obj = new MyClass(10);
System.out.println(obj); // 输出:MyClass{value=10}
}
}
getClass()
方法:
public class MyClass {
public void printClassName() {
Class<? extends MyClass> clazz = this.getClass();
System.out.println(clazz.getName());
}
public static void main(String[] args) {
MyClass obj = new MyClass();
obj.printClassName(); // 输出:MyClass
}
}
wait()
、notify()
和notifyAll()
方法:
public class MyClass {
public synchronized void performTask() {
try {
System.out.println("开始执行任务");
wait();
System.out.println("任务完成");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public synchronized void completeTask() {
notify();
}
public static void main(String[] args) {
MyClass obj = new MyClass();
Thread thread1 = new Thread(() -> {
obj.performTask();
});
Thread thread2 = new Thread(() -> {
try {
Thread.sleep(2000);
obj.completeTask();
} catch (InterruptedException e) {
e.printStackTrace();
}
});
thread1.start();
thread2.start();
}
}
finalize()
方法:
public class MyClass {
@Override
protected void finalize() throws Throwable {
try {
System.out.println("正在执行finalize方法");
} finally {
super.finalize();
}
}
public static void main(String[] args) {
MyClass obj = new MyClass();
obj = null;
System.gc();
}
}
clone()
方法:
public class MyClass implements Cloneable {
private int value;
public MyClass(int value) {
this.value = value;
}
@Override
public Object clone() throws CloneNotSupportedException {
return super.clone();
}
public static void main(String[] args) {
try {
MyClass obj1 = new MyClass(10);
MyClass obj2 = (MyClass) obj1.clone();
System.out.println(obj1 == obj2); // 输出:false
System.out.println(obj1.equals(obj2)); // 输出:true
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
}
}
- 一键测试所有示例
package org.example;
import java.util.Objects;
public class ObjectMethodsExample implements Cloneable{
private int value;
public ObjectMethodsExample(int value) {
this.value = value;
}
/**
* equals()方法示例
*/
@Override
public boolean equals(Object obj) {
// 检查引用是否相同
if (this == obj) {
return true;
}
// 检查对象是否为null以及类型是否相同
if (obj == null || getClass() != obj.getClass()) {
return false;
}
// 将对象转换为当前类类型,并比较字段值是否相等
ObjectMethodsExample other = (ObjectMethodsExample) obj;
return value == other.value;
}
/**
* hashCode()方法示例
*/
@Override
public int hashCode() {
// 使用Objects工具类生成哈希码
return Objects.hashCode(value);
}
/**
* toString()方法示例
*/
@Override
public String toString() {
return "ObjectMethodsExample{" +
"value=" + value +
'}';
}
/**
* getClass()方法示例
*/
public void printClassName() {
Class<? extends ObjectMethodsExample> clazz = this.getClass();
System.out.println(clazz.getName());
}
/**
* wait()、notify()和notifyAll()方法示例
*/
public void performTask() {
synchronized (this) {
try {
System.out.println("开始执行任务");
wait(); // 当前线程进入等待状态
System.out.println("任务完成");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public void completeTask() {
synchronized (this) {
notify(); // 唤醒等待该对象的一个线程
}
}
/**
* finalize()方法示例
*/
@Override
protected void finalize() throws Throwable {
try {
System.out.println("正在执行finalize方法");
} finally {
super.finalize();
}
}
/**
* clone()方法示例
*/
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
public static void main(String[] args) {
ObjectMethodsExample obj1 = new ObjectMethodsExample(10);
ObjectMethodsExample obj2 = new ObjectMethodsExample(10);
// equals()方法示例
boolean isEqual = obj1.equals(obj2);
System.out.println("obj1.equals(obj2): " + isEqual); // 输出:obj1.equals(obj2): true
// hashCode()方法示例
int hashCode = obj1.hashCode();
System.out.println("obj1.hashCode(): " + hashCode); // 输出:obj1.hashCode(): <hashCode值>
// toString()方法示例
String str = obj1.toString();
System.out.println("obj1.toString(): " + str); // 输出:obj1.toString(): ObjectMethodsExample{value=<value>}
// getClass()方法示例
obj1.printClassName(); // 输出:ObjectMethodsExample
// wait()、notify()和notifyAll()方法示例
Thread thread1 = new Thread(() -> {
obj1.performTask();
});
Thread thread2 = new Thread(() -> {
try {
Thread.sleep(2000);
obj1.completeTask();
} catch (InterruptedException e) {
e.printStackTrace();
}
});
thread1.start();
thread2.start();
// clone()方法示例
try {
ObjectMethodsExample clonedObj = (ObjectMethodsExample) obj1.clone();
System.out.println("obj1 == clonedObj: " + (obj1 == clonedObj)); // 输出:obj1 == clonedObj: false
System.out.println("obj1.equals(clonedObj): " + obj1.equals(clonedObj)); // 输出:obj1.equals(clonedObj): true
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
// finalize()方法示例
ObjectMethodsExample obj3 = new ObjectMethodsExample(10);
obj3 = null;
System.gc(); // 垃圾回收
}
}
中文源码
/**
* `Object`类是类层次结构的根类。
* 每个类都将`Object`作为超类。所有对象,包括数组,都实现了该类的方法。
*
* 作者:未指定
* 参见:`java.lang.Class`
* 版本:JDK1.0
*/
public class Object {
private static native void registerNatives();
static {
registerNatives();
}
/**
* 返回此`Object`的运行时类。返回的`Class`对象是由所表示类的`static synchronized`方法锁定的对象。
*
* 实际结果类型是`Class<? extends |X|>`,其中`|X|`是调用`getClass`的表达式的静态类型的擦除。
* 例如,在以下代码片段中不需要进行转换:
*
* ```
* Number n = 0;
* Class<? extends Number> c = n.getClass();
* ```
*
* @return 表示此对象的运行时类的`Class`对象。
* @参考资料 15.8.2 类文本
*/
public final native Class<?> getClass();
/**
* 返回对象的哈希码值。此方法支持散列表(如`java.util.HashMap`)的使用。
*
* `hashCode`的一般契约是:
* - 在Java应用程序的执行过程中,当对同一对象多次调用`hashCode`方法时,
* 如果在对象的`equals`比较中使用的信息未修改,则该方法必须始终返回相同的整数。
* 该整数不需要在应用程序的一个执行与另一个执行之间保持一致。
* - 如果根据`equals(Object)`方法两个对象相等,
* 则对这两个对象中的每个对象调用`hashCode`方法都必须生成相同的整数结果。
* - 如果根据`Object.equals(Object)`方法两个对象不相等,
* 则对这两个对象中的任一对象调用`hashCode`方法都无需生成不同的整数结果。但是,
* 程序员应该知道,对于不相等的对象产生不同的整数结果可能会提高散列表的性能。
*
* 尽管可以合理地实现由类`Object`定义的`hashCode`方法,以使得对于不同的对象返回不同的整数,
* 但这不是Java编程语言所要求的。
*
* @return 此对象的哈希码值。
* @参见 `java.lang.Object#equals(java.lang.Object)`
* @参见 `java.lang.System#identityHashCode`
*/
public native int hashCode();
/**
* 指示某个其他对象是否与此对象“相等”。
*
* `equals`方法在非空对象引用上实现了等价关系:
* - 它是自反的:对于任何非空引用值`x`,`x.equals(x)`应该返回`true`。
* - 它是对称的:对于任何非空引用值`x`和`y`,
* 如果`x.equals(y)`返回`true`,则`y.equals(x)`必须返回`true`。
* - 它是传递的:对于任何非空引用值`x`、`y`和`z`,
* 如果`x.equals(y)`返回`true`且`y.equals(z)`返回`true`,
* 则`x.equals(z)`必须返回`true`。
* - 它是一致的:对于任何非空引用值`x`和`y`,
* 多次调用`x.equals(y)`始终返回`true`或始终返回`false`,
* 前提是在比较对象时使用的信息未修改。
* - 对于任何非空引用值`x`,`x.equals(null)`应该返回`false`。
*
* 类`Object`的`equals`方法实现了最具有区分性可能的对象等价关系;
* 也就是说,对于任何非空引用值`x`和`y`,
* 如果此方法返回`true`,则`x`和`y`引用同一个对象(`x == y`的值为`true`)。
*
* 请注意,通常情况下,需要覆盖`hashCode`方法,以便在覆盖此方法时保持`hashCode`方法的一般契约,
* 该契约指出相等的对象必须具有相等的哈希码。
*
* @param obj 要与之进行比较的参考对象。
* @return 如果此对象与`obj`参数相同,则返回`true`;否则返回`false`。
* @参见 `#hashCode()`
* @参见 `java.util.HashMap`
*/
public boolean equals(Object obj) {
return (this == obj);
}
/**
* 创建并返回此对象的副本。"复制"的确切含义可能取决于对象的类。
* 通常的意图是,对于任何对象`x`,表达式:
* ```
* x.clone() != x
* ```
* 将为真,并且表达式:
* ```
* x.clone().getClass() == x.getClass()
* ```
* 将为`true`,但这些不是绝对要求。
*
* 按照约定,应通过调用`super.clone`来获得返回的对象。如果一个类及其所有超类(除了`Object`)都遵守此约定,
* 那么将有`x.clone().getClass() == x.getClass()`的情况。
*
* 按照约定,此方法返回的对象应该独立于正在克隆的对象(即,被克隆的对象)。
* 为了实现这种独立性,可能需要在返回之前修改`super.clone`返回的对象的一个或多个字段。
* 通常,这意味着复制构成对象内部"深层结构"的任何可变对象,并用对这些对象的引用替换对副本的引用。
* 如果一个类只包含原始字段或对不可变对象的引用,那么通常情况下,
* 不需要修改由`super.clone`返回的对象中的字段。
*
* 类`Object`的`clone`方法执行了一次特定的克隆操作。首先,如果此对象的类未实现接口`Cloneable`,则抛出`CloneNotSupportedException`。
* 注意,所有数组都被认为实现了接口`Cloneable`,并且数组类型`T[]`的`clone`方法的返回类型是`T[]`,其中T是任何引用或原始类型。
* 否则,此方法将创建此对象类的新实例,并使用该对象的相应字段的内容初始化所有字段,就像通过赋值一样;字段的内容本身不被克隆。
* 因此,此方法执行的是对此对象的"浅拷贝",而不是"深拷贝"操作。
*
* 类`Object`本身不实现接口`Cloneable`,因此在运行时调用其类为`Object`的对象上的`clone`方法将导致抛出异常。
*
* @return 此实例的克隆。
* @throws CloneNotSupportedException 如果对象的类不支持`Cloneable`接口。
* 如果覆盖了`clone`方法的子类也可以抛出此异常,以指示无法克隆一个实例。
* @参见 `java.lang.Cloneable`
*/
protected native Object clone() throws CloneNotSupportedException;
}
/**
* 返回对象的字符串表示。一般来说,toString方法返回一个文本表示该对象的字符串。
* 结果应该是简明但信息丰富的表示形式,方便人阅读。
* 推荐所有子类重写这个方法。
*
* Object类的toString方法返回一个字符串,它由对象所属类的名称、at符号"@"以及对象的哈希码的无符号十六进制表示组成。
* 换句话说,该方法返回一个与以下值相等的字符串:
*
* getClass().getName() + '@' + Integer.toHexString(hashCode())
*
* @return 对象的字符串表示。
*/
public String toString() {
return getClass().getName() + "@" + Integer.toHexString(hashCode());
}
/**
* 唤醒正在此对象的监视器上等待的单个线程。
* 如果有任何线程在等待该对象,则选择其中一个线程唤醒。
* 选择是任意的,并由实现自行决定。
* 线程通过调用wait方法在对象的监视器上等待。
*
* 被唤醒的线程在当前线程释放对该对象的锁定之前无法继续执行。
* 被唤醒的线程将以通常的方式与可能正在积极竞争以同步此对象的其他线程竞争;
* 例如,被唤醒的线程在作为下一个锁定此对象的线程方面没有可靠的优势或劣势。
*
* 只有一个线程可以同时拥有对象的监视器。
*
* @throws IllegalMonitorStateException 如果当前线程不是该对象的监视器的所有者。
* @see java.lang.Object#notifyAll()
* @see java.lang.Object#wait()
*/
public final native void notify();
/**
* 唤醒正在此对象的监视器上等待的所有线程。
* 一个线程通过调用wait方法在对象的监视器上等待。
*
* 被唤醒的线程在当前线程释放对该对象的锁定之前无法继续执行。
* 被唤醒的线程将以通常的方式与可能正在积极竞争以同步此对象的其他线程竞争;
* 例如,被唤醒的线程在作为下一个锁定此对象的线程方面没有可靠的优势或劣势。
*
* 只有一个线程可以同时拥有对象的监视器。
*
* @throws IllegalMonitorStateException 如果当前线程不是该对象的监视器的所有者。
* @see java.lang.Object#notify()
* @see java.lang.Object#wait()
*/
public final native void notifyAll();
/**
* 导致当前线程等待,直到另一个线程调用该对象的notify()方法或notifyAll()方法,
* 或者指定的时间已经过去。
*
* 当前线程必须拥有此对象的监视器。
*
* 该方法使当前线程(称为T)将自身置于此对象的等待集中,然后放弃对此对象的任何和所有同步声明。
* 线程T对于线程调度目的而言是不可用的,并且处于休眠状态,直到发生以下四种情况之一:
*
* - 其他线程调用了该对象的notify()方法,且线程T恰好被选择为唤醒的线程。
* - 其他线程调用了该对象的notifyAll()方法。
* - 其他线程中断了线程T。
* - 经过指定的实时时间,或者更长时间。如果timeout为0,则不考虑实际时间,线程仅在收到通知时等待。
*
* 然后,线程T从此对象的等待集中移除,并重新启用以进行线程调度。
* 然后,它以通常的方式与其他线程竞争,以获取对该对象的锁定权;
* 一旦获得了对象的控制权,它的所有同步声明都会恢复到先前的状态,即wait()方法被调用时的状态。
* 然后,线程T从wait()方法的调用返回。
* 因此,从wait()方法返回时,对象的同步状态和线程T的同步状态与调用wait()方法时的状态完全相同。
*
* 线程也可以在没有被通知、中断或超时的情况下唤醒,这种情况称为虚假唤醒。
* 虽然在实践中很少发生,但应用程序必须通过测试应该导致线程被唤醒的条件,并在条件不满足时继续等待来防范虚假唤醒。
* 换句话说,等待应该始终在循环中进行,如下所示:
*
* synchronized (obj) {
* while (<condition does not hold>)
* obj.wait(timeout);
* ... // 根据条件执行相应的操作
* }
*
* @param timeout 最长等待时间(以毫秒为单位)。
* @throws IllegalArgumentException 如果timeout的值为负数。
* @throws IllegalMonitorStateException 如果当前线程不是该对象的监视器的所有者。
* @throws InterruptedException 如果任何线程在当前线程等待通知之前或期间中断了当前线程。
* 抛出此异常时,当前线程的中断状态将被清除。
* @see java.lang.Object#notify()
* @see java.lang.Object#notifyAll()
*/
public final native void wait(long timeout) throws InterruptedException;
/**
* 导致当前线程等待,直到另一个线程调用该对象的notify()方法或notifyAll()方法,
* 或者某个其他线程中断了当前线程,或者已经过去了一定的实际时间。
*
* 此方法与具有一个参数的wait方法类似,但它允许更精细地控制等待通知的时间。
* 实际时间以纳秒为单位,给定如下:
*
* 1000000 * timeout + nanos
*
* 在其他方面,此方法与具有一个参数的wait方法相同。
* 特别是,wait(0, 0)与wait(0)具有相同的意义。
*
* 当前线程必须拥有此对象的监视器。
* 线程释放此监视器的所有权,并等待,直到发生以下两种情况之一:
*
* - 另一个线程通过调用notify或notifyAll方法通知了正在等待该对象监视器的线程。
* - 指定的时间(由timeout毫秒和nanos纳秒参数指定)已经过去。
*
* 然后,线程将等待,直到它可以重新获得监视器的所有权并恢复执行。
*
* 与具有一个参数的版本一样,中断和虚假唤醒是可能的,因此应在循环中使用此方法:
*
* synchronized (obj) {
* while (<condition does not hold>)
* obj.wait(timeout, nanos);
* ... // 根据条件执行相应的操作
* }
*
* @param timeout 最长等待时间(以毫秒为单位)。
* @param nanos 附加时间,以纳秒为单位,范围为0-999999。
* @throws IllegalArgumentException 如果timeout的值为负数,或者nanos的值不在0-999999的范围内。
* @throws IllegalMonitorStateException 如果当前线程不是该对象的监视器的所有者。
* @throws InterruptedException 如果任何线程在当前线程等待通知之前或期间中断了当前线程。
* 抛出此异常时,当前线程的中断状态将被清除。
*/
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 > 0) {
timeout++;
}
wait(timeout);
}
/**
* 导致当前线程等待,直到另一个线程调用该对象的notify()方法或notifyAll()方法。
* 换句话说,该方法的行为就像简单地执行wait(0)一样。
*
* 当前线程必须拥有此对象的监视器。线程释放此监视器的所有权,并等待,直到其他线程通过调用notify方法或notifyAll方法通知等待该对象监视器的线程唤醒。
* 然后,线程将等待,直到它可以重新获得监视器的所有权并恢复执行。
*
* 与具有一个参数的版本一样,中断和虚假唤醒是可能的,因此应在循环中使用此方法:
*
* synchronized (obj) {
* while (<condition does not hold>)
* obj.wait();
* ... // 根据条件执行相应的操作
* }
*
* @throws IllegalMonitorStateException 如果当前线程不是该对象的监视器的所有者。
* @throws InterruptedException 如果任何线程在当前线程等待通知之前或期间中断了当前线程。
* 抛出此异常时,当前线程的中断状态将被清除。
* @see java.lang.Object#notify()
* @see java.lang.Object#notifyAll()
*/
public final void wait() throws InterruptedException {
wait(0);
}
/**
* 在垃圾收集确定不再有对该对象的引用时,在对象上调用垃圾收集器。
* 子类重写finalize方法以释放系统资源或执行其他清理操作。
*
* finalize方法的一般约定是,
* 当Java虚拟机确定没有任何方式可以访问此对象的任何线程(除非由于准备终结另一个对象或类而导致的最终处理)时,将调用它。
* finalize方法可以采取任何操作,包括再次使此对象对其他线程可用;然而,finalize的常见目的是在对象被不可撤销地丢弃之前执行清理操作。
* 例如,表示输入/输出连接的对象的finalize方法可能会在永久丢弃对象之前执行显式的I/O事务。
*
* Object类的finalize方法不执行任何特殊操作;它只是正常返回。
* Object的子类可以重写此定义。
*
* Java编程语言不保证哪个线程将调用给定对象的finalize方法。
* 但是,保证调用finalize的线程在调用finalize时不会持有任何对用户可见的同步锁。
* 如果finalize方法抛出未捕获的异常,则忽略该异常并终止该对象的终结。
*
* 在调用finalize方法后,不会执行任何其他操作,直到Java虚拟机再次确定没有任何方式可以访问此对象的任何线程,
* 包括可能由其他对象或类进行的操作以准备最终处理该对象的操作,然后可以丢弃该对象。
*
* 对于给定对象,Java虚拟机永远不会多次调用finalize方法。
*
* finalize方法抛出的任何异常都会停止对象的终结,但否则被忽略。
*
* @throws Throwable 由该方法引发的异常
* @see java.lang.ref.WeakReference
* @see java.lang.ref.PhantomReference
* @jls 12.6 类实例的终结
*/
protected void finalize() throws Throwable { }
}