关于JAVA核心技术(卷一)读后的思考(回调,clone的讨论)

Posted zzuzhouxiang

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了关于JAVA核心技术(卷一)读后的思考(回调,clone的讨论)相关的知识,希望对你有一定的参考价值。

回调

回调是一种常见的程序设计模式。这种模式中,可以指出某个特定事件发生时应该采取的动作。

直接给上代码

package com.java.timer;

import java.awt.event.ActionListener;

import javax.swing.JOptionPane;
import javax.swing.Timer;

public class TimerTest {

    public static void main(String[] args) {
        // TODO Auto-generated method stub
        ActionListener listener=new TimePrinter();
        Timer t = new Timer(10000,listener);
        t.start();
        JOptionPane.showMessageDialog(null, "Quit program?");
        System.exit(0);
        

    }

}
package com.java.timer;

import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Date;

public class TimePrinter implements ActionListener {

    @Override
    public void actionPerformed(ActionEvent event) {
        // TODO Auto-generated method stub
        System.out.println("At the tone,the time is "+new Date());
        Toolkit.getDefaultToolkit().beep();
    }

}

这里调用了java.swing包中的Timer类,可以使用它在给定的时间间隔时发出通告

我们这里可以分析下这段代码。构造一个TimePrinter类调用ActionListener接口,而这个类对这个方法的实现,是通过构造Date对象,紧接着调用静态方法deep()进行提示。

 ActionListener listener=new TimePrinter();
这个语句的意思是声明一个接口类型的变量,然后new一个TimePrinter对象。利用接口型变量对其存储。

紧接着利用Timer方法构造一个定时器,调用接口变量为其中之一的参数,最后调用JOptionPane()方法来构造一个对话框,整个过程就完成了。

这个过程就体现出了回调这个设计模式的思想。在后面的博客中我应该会总结Java的设计模式。

 

对象克隆

这里要说到对象克隆的知识了。这里我们就会讨论一个Cloneable接口,这个接口只是一个类提供了一个安全的clone()方法。

这里可以举个例子,

Employee original = new Employee("John Public",50000);
Employee copy =original;
copy.raiseSalary(10);

我们来分析一下这段代码,第一句new了一个Employee对象,将对象存储地址保存在original中,而第二句则将original中存储的对象复制了一份到copy变量中去了,这样的话original和copy指向的都是同一个地址,也就是那个实例地址存储在这两个变量中,所以第三句对copy进行修改,同时也对original进行修改了。

而我们希望拷贝一份与原来无关的变量,那这样就要用到clone方法了。

Employee original = new Employee("John Public",50000);
Employee copy = original.clone();
copye.raiseSalary(10);

clone方法是Object的一个protect方法,说明代码不能直接调用这个方法,只有子类或者相同的类才可以克隆父类对象。这个限制是有原因的,我们可以从Object如何实现clone方法来想。因为其对这个对象是一无所知的,只能逐个域的进行拷贝。

这里我们就要讨论一下clone的分类:

它分为深拷贝浅拷贝

默认的克隆操作是“浅拷贝”,浅拷贝有什么影响,是要看具体情况的,如果原对象和浅克隆对象共享的子对象是不可变的,那么这种共享就是安全的。如果子对象属于一个不可变的类,如String,简而言之,就是所有的量不可改变的量是,浅拷贝是安全的。如果存在可变的量,就要对clone方法建立一个深拷贝。

对于每一个类,需要确定:

1)默认的clone方法是否满足要求;

2)是否可以在可变的子对象上调用clone来修补clone方法;

3)是否不该使用clone;

如果一个对象请求克隆,但并没有实现这个接口,就会生成一个受查异常。Cloneable接口是Java提供的一组标记接口之一,正常接口一般是确保一个类实现一个或一组特定的方法。标记接口不包含任何方法,它唯一的作用是允许在类型查询中使用instanceof。即使浅拷贝实现能满足要求,但还是要实现Cloneable接口,将clone重新定义为public,再调用super.clone()。

代码:

class Employee implements Cloneable
{
public Employee clone() throws CloneNotSupportedException
{
return (Employee)super.clone();
}
……}

与Object.clone提供的浅拷贝相比,前面看到的方法并没有增加任何功能,只是将其设为公有的。要建立深拷贝,需要更多工作,克隆对象中可变的实例域。

下面是一个例子:

class Employee  implements Cloneable
{
……
   public Employee clone() throws CloneNotSupportedException
  {
     Employee cloned =(Employee) super.clone();
     Cloned.hireDay=(Date)hireDay.clone();
     return cloned;
   }
}

如果都在一个对象上调用clone,但这个对象的类并没有实现Cloneable,这个clone方法就会抛出一个异常。虽然Employee和Date类实现了Clone接口,但是编译器并不知道,所有直接throws这个异常。

这里要注意一个问题,就是子类的克隆,假设我们已经定义了Employee类的clone方法,这时候,就要知道,任何人都会用它来克隆Manager,这时候就要取决于Manager的域了,如果增加的域都是基本数据类型或者是不可变类,那就没有问题,如果不是的话,那就需要重新定义clone方法。

 

总而言之,其实很简单,浅拷贝就是默认拷贝,不需要克隆对象中的可变实例域,只需要将clone方法定义为public类型就可以了

深拷贝就是需要重新定义clone()方法,使可变类实现拷贝,两者都要对其进行异常处理。

 

以上是关于关于JAVA核心技术(卷一)读后的思考(回调,clone的讨论)的主要内容,如果未能解决你的问题,请参考以下文章

关于JAVA核心技术(卷一)读后的思考(equals方法的讨论)

关于JAVA核心技术(卷一)读后的思考(用户自定义类,静态域和静态方法的思考以及方法参数)

关于JAVA核心技术(卷一)读后的思考(泛型数组列表的讨论)

关于JAVA核心技术(卷一)读后的思考(接口的基本知识的讨论)

关于JAVA核心技术(卷一)读后的思考(对象与类,日历的构造)

关于JAVA核心技术(卷一)读后的思考(lambda表达式的讨论)