关于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()方法,使可变类实现拷贝,两者都要对其进行异常处理。

原文地址:https://www.cnblogs.com/zzuzhouxiang/p/10354252.html

时间: 2024-08-30 11:32:33

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

关于JAVA核心技术(卷一)读后的思考(内部类的讨论)

内部类 内部类是定义在另一个类中的类. 定义内部类的原因有: 1)内部类方法可以访问该类定义所在的作用域中的数据,包括私有的数据. 2)内部类可以对同一个包中的其他类隐藏起来. 3)当想要定义一个回调函数且不想编写大量代码时,使用匿名内部类比较便捷. 使用内部类访问对象状态 分析一下下面一段代码 public class TalkingClock { private int interval; private boolean beep; public TalkingClock(int inter

java核心技术卷一

java核心技术卷一 java基础类型 整型 数据类型 字节数 取值范围 int 4 +_2^4*8-1 short 2 +_2^2*8-1 long 8 +_2^8*8-1 byte 1 -128-127       浮点类型 数据类型 字节数 取值范围 小数位数 float 4 10^-38~10^38和-10^-38~-10^38 小数位数6-7 double 4 10^-308~10^308和-10^-308~-10^308 15位小数         boolean 类型和char 类

读《java核心技术卷一》有感

过去一个多月了吧.才囫囵吞枣地把这书过了一遍.话说这书也够长的,一共706页.我从来不是个喜欢记录的人,一直以来看什么书都是看完了就扔一边去,可能有时候有那么一点想记录下来的冲动,但算算时间太紧,很多也是有始无终,毕竟在之前研究研究程序也只是自己的一个爱好而已,但没有想到签了一个程序员的工作.唉,这老天也太捉弄人了吧,让一个学电气工程(强电方向)学生毕业之后去写代码,而且是与硬件完全无关的代码.真是白念几年大学了.行了,就行发这么多牢骚吧. <java核心技术>有两个卷,我只看了卷一,从我的感

Java核心技术 卷一 笔记六 Date类

在Java核心技术卷就行了一前期  date类出现的频率很高  所以就对date类进行了小小的整合 Date类有两个 date类 表示特定时间的类 这个构造函数分配一个Date对象并初始化它代表指定的毫秒数,因为被称为"纪元",即1970年1月1日00:00:00 GMT标准基准时间. 就像格林尼治时间一样  作为一种基准值而存在 一般常用的是date转为string类型 String s=new Date(0).toString(); System.out.println(s.toS

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

接口 接口技术:这种技术主要用来描述类具有什么功能,而并不给出每个功能的具体实现.一个类可以实现一个或多个接口,并在需要接口的地方,随时使用实现了相应接口对象. 接口概念:接口不是类,而是对类的一组需求的描述,这些类要遵从接口描述的统一格式进行定义. 举个简单的例子:假设有一个类A,其中有一个sort方法是对对象数组进行排序,但要求对象所属的类必须实现了 B接口.假设B接口定义如下: public interface B{ int compareTo(Object other); } 即所有实现

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

lambda表达式 lambda表达式是一个可传递的代码块.可以以后执行一次或者多次.在程序运行中我们经常会遇到传递代码段的情况,但是我们一般都是先构造一个对象,然后通过对象调用相应的代码块来实现传递代码块的目的,这个方法十分繁琐,设计师为解决这个问题,就设计出了lambda表达式. lambda表达式的语法我们可以参考之前写的方法,可以发现如果方法可以分为方法名,参数和方法主体.lambda表达式就是将方法名省去: 标准情况: (参数类型1 参数1,参数类型2 参数2,.....,参数类型n

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

关于这本书,前三张都是基本内容,我觉得个人掌握的还可以,所以从第四章开始整理每日所学. 第四章主要说的是对象和类.第一部分是面向对象程序设计的概述.其中面向对象程序设计简写OOP,接下来写的是类,即构造对象的模板,由类构造对象的过程称创建类的实例(instance)这里可以想到instanceof,这也在后面学习中会有提到 封装是将数据和行为组合到一个包中,并对对象的使用者隐藏了数据的实现方式.数据成为实例域,操纵数据的过程称为方法.封装赋予了对象"黑盒"的特征,这是提高重用性和可靠性

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

用户自定义类: 这部分并没有太过于困难的部分,借由代码进行复习: Employee类的定义: package com.java.EmployeeTest; import java.time.*; public class Employee {    private String name;    private double salary;    private LocalDate hireDay;//以上分别是Employee类的实例域        public Employee(Strin

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

这是我反复看了两遍才理解的部分.其中也不乏参考了他人的微博内容,才大致对这个方法有所理解. 首先我们从Object类开始说起, 书中已经说了Object类是Java中所有类的始祖,在Java中的每个类都是由他扩展而来的,但在现实使用中并没有要求写出.如果一个类并没有明确指出超类,Object就是被认为是这个类的超类. 可以用Object类型的变量引用任何类型的对象: Object obj = new Employee("Harry Hacker",35000); 正如昨天的博文所提到过

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

在C++中编译时是要确定数组大小的,而Java有所不同,它允许在运行时确定数组的大小.但是如果仅通过数组是无法改变运行时无法动态更改数组的问题.一旦确定了数组大小,就很难改变他了数组的大小了,要解决这个问题,就需要引入ArrayList的类.它使用起来有点像数组,但在添加或删除元素时,具有自动调节数组容量的功能,而不需要为此编写任何代码. ArrayList是一个采用类型参数的泛型类.为了指定数组列表保存的元素对象类型,需要用一对尖括号将类名括起来加在后面.下面是声明和构造一个保存Employe