JavaSE基础学习,今天我们花3min回顾一下Object的finalize和clone方法。
先回顾finalize,看最好的教材,官方API文档:
finalize
protected void finalize() throws Throwable
-
当垃圾回收器确定不存在对该对象的更多引用时,由对象的垃圾回收器调用此方法。
子类重写
finalize
方法,以配置系统资源或执行其他清除。finalize 的常规协定是:当 JavaTM 虚拟机已确定尚未终止的任何线程无法再通过任何方法访问此对象时,将调用此方法,除非由于准备终止的其他某个对象或类的终结操作执行了某个操作。finalize 方法可以采取任何操作,其中包括再次使此对象对其他线程可用;不过,finalize 的主要目的是在不可撤消地丢弃对象之前执行清除操作。例如,表示输入/输出连接的对象的 finalize 方法可执行显式 I/O 事务,以便在永久丢弃对象之前中断连接。
Object 类的 finalize 方法执行非特殊性操作;它仅执行一些常规返回。Object 的子类可以重写此定义。
Java 编程语言不保证哪个线程将调用某个给定对象的 finalize 方法。但可以保证在调用 finalize 时,调用 finalize 的线程将不会持有任何用户可见的同步锁定。如果 finalize 方法抛出未捕获的异常,那么该异常将被忽略,并且该对象的终结操作将终止。
在启用某个对象的 finalize 方法后,将不会执行进一步操作,直到 Java 虚拟机再次确定尚未终止的任何线程无法再通过任何方法访问此对象,其中包括由准备终止的其他对象或类执行的可能操作,在执行该操作时,对象可能被丢弃。
对于任何给定对象,Java 虚拟机最多只调用一次 finalize 方法。
finalize
方法抛出的任何异常都会导致此对象的终结操作停止,但可以通过其他方法忽略它。 -
-
抛出:
-
Throwable
- 此方法抛出的Exception
-
简单了解一下。
然后是clone:
clone
protected Object clone() throws CloneNotSupportedException
-
创建并返回此对象的一个副本。“副本”的准确含义可能依赖于对象的类。这样做的目的是,对于任何对象
x,表达式:
x.clone() != x
x.clone().getClass() == x.getClass()
x.clone().equals(x)
按照惯例,返回的对象应该通过调用 super.clone 获得。如果一个类及其所有的超类(Object 除外)都遵守此约定,则x.clone().getClass() == x.getClass()。
按照惯例,此方法返回的对象应该独立于该对象(正被复制的对象)。要获得此独立性,在 super.clone 返回对象之前,有必要对该对象的一个或多个字段进行修改。这通常意味着要复制包含正在被复制对象的内部“深层结构”的所有可变对象,并使用对副本的引用替换对这些对象的引用。如果一个类只包含基本字段或对不变对象的引用,那么通常不需要修改super.clone 返回的对象中的字段。
Object 类的 clone 方法执行特定的复制操作。首先,如果此对象的类不能实现接口 Cloneable,则会抛出CloneNotSupportedException。注意,所有的数组都被视为实现接口 Cloneable。否则,此方法会创建此对象的类的一个新实例,并像通过分配那样,严格使用此对象相应字段的内容初始化该对象的所有字段;这些字段的内容没有被自我复制。所以,此方法执行的是该对象的“浅表复制”,而不“深层复制”操作。
Object 类本身不实现接口 Cloneable,所以在类为 Object 的对象上调用 clone 方法将会导致在运行时抛出异常。
-
-
返回:
- 此实例的一个副本。 抛出:
-
CloneNotSupportedException
- 如果对象的类不支持Cloneable
接口,则重写clone
方法的子类也会抛出此异常,以指示无法复制某个实例。
另请参见:
-
Cloneable
温馨提示:这两个方法都是protected。
代码实战,在Employee中重写clone方法:
@Override
protected Object clone() throws CloneNotSupportedException {
// TODO Auto-generated method stub
return super.clone();
}
然后在main中测试:
public static void main(String[] args) throws CloneNotSupportedException {
Employee e = new Employee();
Object object = e.clone();
Employee e2 = (Employee) object;
}
Duang一下就报错了:
Exception in thread "main" java.lang.CloneNotSupportedException: ···.Employee
at java.lang.Object.clone(Native Method)
at day0709101112_object.Employee.clone(Employee.java:90)
at day0709101112_object.CloneTest.main(CloneTest.java:12)
Why?
因为Employee没实现Cloneable接口,现在补上:
public class Employee implements Cloneable{
此时运行,一切正常。
那么Cloneable又是个什么鬼?
public interface Cloneable
此类实现了 Cloneable
接口,以指示 Object.clone()
方法可以合法地对该类实例进行按字段复制。
如果在没有实现 Cloneable
接口的实例上调用 Object 的 clone 方法,则会导致抛出CloneNotSupportedException
异常。
按照惯例,实现此接口的类应该使用公共方法重写 Object.clone(它是受保护的)。请参阅Object.clone()
,以获得有关重写此方法的详细信息。
注意,此接口不 包含 clone 方法。因此,因为某个对象实现了此接口就克隆它是不可能的。即使 clone 方法是反射性调用的,也无法保证它将获得成功。
-
从以下版本开始:
- JDK1.0 另请参见:
-
CloneNotSupportedException
,Object.clone()
这个接口是标记接口,标记实现了Cloneable
接口,以指示Object.clone()
方法可以合法地对该类实例进行按字段复制。
测试效果:
Employee e = new Employee("A","20");
Object object = e.clone();
Employee e2 = (Employee) object;
System.out.println(e);
System.out.println(e2);
输出:
Employee [name=A, age=20]
Employee [name=A, age=20]
我们在测一下代码:
Employee e3 = e;
System.out.println(e3);
输出:
Employee [name=A, age=20]
这克隆好像没啥意义?
非也,我们继续测试代码:
e3.setName("B");
e3.setAge("30");
System.out.println("e:" + e);
System.out.println("e2:" + e2);
System.out.println("e3:" + e3);
输出:
e:Employee [name=B, age=30]
e2:Employee [name=A, age=20]
e3:Employee [name=B, age=30]
因此克隆,克出一份一模一样的东西,和原东西没啥关系。
两个引用指向同一个对象,改动有关系。