面向对象之深复制与浅复制

前言:

  基于面向对象的思想,大部分的类都可视为“工具”。那么对于工具的使用,我们总是期望能高效而又方便。特别是当我们在重复实现某些功能的时候,那有没有一种能快速复用类的捷径呢?

  既然提出来,答案当然是肯定的。“Copy”----复制。

  查看Java中的Object这个祖先类我们可以发现,该类含有一个clone()方法,并且返回“Object”类型。不过,方法的前面还有“native”关键字,其表示Object类使用其方法时是编译器内部执行的,对外界不可正常访问。

  回到正题,什么样的类才可以进行克隆呢?----实现Cloneable接口。常见的Calendar类和Date工具类都已实现了该接口,所以可以直接进行克隆。下面我们自己写一个实现Cloneable接口的类进行测试。

创建House类及Wall类,其中House类与Wall类属于组合关系。

 1 package clonable;
 2
 3 public class House implements Cloneable {
 4
 5     // field
 6
 7     private int id;
 8     private double area;
 9     private Wall wall;
10
11     public Wall getWall() {
12         return wall;
13     }
14
15     public void setWall(Wall wall) {
16         this.wall = wall;
17     }
18
19     public double getArea() {
20         return area;
21     }
22
23     public House() {
24         id = 1;
25         area = 170.5;
26         wall = new Wall();
27     }
28
29     public House(double area) {
30         super();
31         this.area = area;
32     }
33
34     public void setArea(double area) {
35         this.area = area;
36     }
37
38     public int getId() {
39         return id;
40     }
41
42     public void setId(int id) {
43         this.id = id;
44     }
45     /*
46     @Override
47     public Object clone() throws CloneNotSupportedException {
48         House house = (House) super.clone(); // clone self
49         house.setWall((Wall) house.getWall().clone()); // refresh ‘wall‘ as type
50                                                         // of Wall
51         return house;
52     }
53     */
54     @Override
55     public Object clone() throws CloneNotSupportedException {
56         return super.clone();
57     }
58
59     // show the detail message about the house
60
61     public void show() {
62         System.out.println("area: " + getArea() + ",and the color of wall is:"
63                 + wall.getColor());
64
65     }
66
67 }
 1 package clonable;
 2
 3 public class Wall implements Cloneable{
 4
 5     private String color=null;
 6
 7     public String getColor(){
 8         return color;
 9     }
10
11     public void setColor(String color) {
12         this.color = color;
13     }
14
15     @Override
16     public Object clone() throws CloneNotSupportedException {
17         return super.clone();
18     }
19
20
21 }

测试程序:

 1 package clonable;
 2
 3 import java.util.Date;
 4
 5 public class Client {
 6
 7     public static void main(String[] args) throws Exception{
 8
 9
10         System.out.println("---Clone test!---");
11         House h1 = new House();
12         h1.getWall().setColor("Blue");
13         House h2 = (House)h1.clone();
14         h2.getWall().setColor("Pink");
15         House h3 = (House)h1.clone();
16         h3.getWall().setColor("Black");
17
18         h1.show();
19         h2.show();
20         h3.show();
21     }
22
23 }

测试结果:

---Clone test!---
area: 170.5,and the color of wall is:Black
area: 170.5,and the color of wall is:Black
area: 170.5,and the color of wall is:Black

从结果中我们发现,除了基本类型的值可以进行克隆以外,引用类型无法实现复制。一个set操作,将wall.color属性全部改为black。

大家看出所以然了麽。其实,这就是所谓的“浅复制(shadow copy)”。其大概意思指的是对实现了Cloneable接口的对象进行克隆的时候,值对象可直接复制,而引用对象只是复制其“引用”而已。所以,才会出现最后的h3的set操作改变了前面h1和h2设置的wall.color属性。具体,可参考下图:

图一:浅复制

思考一下,如何实现“深复制”?即在复制基本类型的同时,还能复制引用类型做指向的对象。

解决方法是这样的,首先得确定引用对象实现了Cloneable接口。然后,我们重写House类的clone()方法对引用对象同样进行克隆操作。最后将其set回house对象,这样便实现了深复制!

---修改后的House类----

 1 package clonable;
 2
 3 public class House implements Cloneable {
 4
 5     // field
 6
 7     private int id;
 8     private double area;
 9     private Wall wall;
10
11     public Wall getWall() {
12         return wall;
13     }
14
15     public void setWall(Wall wall) {
16         this.wall = wall;
17     }
18
19     public double getArea() {
20         return area;
21     }
22
23     public House() {
24         id = 1;
25         area = 170.5;
26         wall = new Wall();
27     }
28
29     public House(double area) {
30         super();
31         this.area = area;
32     }
33
34     public void setArea(double area) {
35         this.area = area;
36     }
37
38     public int getId() {
39         return id;
40     }
41
42     public void setId(int id) {
43         this.id = id;
44     }
45
46     @Override
47     public Object clone() throws CloneNotSupportedException {
48         House house = (House) super.clone(); // clone self
49         house.setWall((Wall) house.getWall().clone()); // refresh ‘wall‘ as type
50                                                         // of Wall
51         return house;
52     }
53     /*
54     @Override
55     public Object clone() throws CloneNotSupportedException {
56         return super.clone();
57     }
58     */
59
60     // show the detail message about the house
61     public void show() {
62         System.out.println("area: " + getArea() + ",and the color of wall is:"
63                 + wall.getColor());
64
65     }
66
67 }

测试结果:

---Clone test!---
area: 170.5,and the color of wall is:Blue
area: 170.5,and the color of wall is:Pink
area: 170.5,and the color of wall is:Black

图二:深复制

时间: 2024-10-09 12:36:20

面向对象之深复制与浅复制的相关文章

iOS 集合的深复制与浅复制

概念 对象拷贝有两种方式:浅复制和深复制.顾名思义,浅复制,并不拷贝对象本身,仅仅是拷贝指向对象的指针:深复制是直接拷贝整个对象内存到另一块内存中. 一图以蔽之 再简单些说:浅复制就是指针拷贝:深复制就是内容拷贝. 集合的浅复制 (shallow copy) 集合的浅复制有非常多种方法.当你进行浅复制时,会向原始的集合发送retain消息,引用计数加1,同时指针被拷贝到新的集合. 现在让我们看一些浅复制的例子: NSArray *shallowCopyArray = [someArray cop

深复制与浅复制

概念 对象拷贝有两种方式:浅复制和深复制.顾名思义,浅复制,并不拷贝对象本身,仅仅是拷贝指向对象的指针:深复制是直接拷贝整个对象内存到另一块内存中. 一图以蔽之 再简单些说:浅复制就是指针拷贝:深复制就是内容拷贝. 集合的浅复制 (shallow copy) 集合的浅复制有非常多种方法.当你进行浅复制时,会向原始的集合发送retain消息,引用计数加1,同时指针被拷贝到新的集合. 现在让我们看一些浅复制的例子: NSArray *shallowCopyArray = [someArray cop

OC 中 的copy 功能 深复制 和 浅复制 的 区别

系统的类要是实现copy拷贝的功能,必须先签订拷贝NSCopying的协议,然后实现对应的方法 在.h文件中得@interface Boy : NSObject 的后面需要签订拷贝NSCopying的协议 例子: 在.h文件中 @interface Boy : NSObject<NSCopying> 1. Boy类使用copy的方法 例子: Boy *boy =[Boy boyWithName:@"zhangyangyang" hobby:@"wan"]

.NET中深复制与浅复制

概述: 在.NET里面,提供对象复制的功能,前提是实现ICloneable接口.ICloneable接口中有一个Clone方法, 可以在类中覆写实现自定义的拷贝方法.对象复制的实现方法有两种:深复制和浅复制. 深复制和浅复制: 浅复制,浅复制是指源对象与复制出来的对象共用一份实体,对其中任何一个对象的改动都会影响另外一个对象.相当于复制了指针. 深复制:指源对象与复制对象互相独立,为新对象重新分配了一段内存空间,并复制源对象的内容.其中任何一个对象的改动都不会对另外一个对象造成影响. 深浅复制与

C++学习基础七——深复制与浅复制

一.深复制与浅复制基本知识 深复制和浅复制,又称为深拷贝和浅拷贝. 深复制和浅复制的区别如下图1所示: 图1 图1表示的是,定义一个类CDemo,包含int a和char *str两个成员变量, 当深复制时,A中的指针str与B中的指针str指向不同的地址,只是地址所指向的数据相同. 当浅复制时,A中的指针str与B中的指针str指向相同的地址. 1.浅复制:如果我们自己不实现复制构造函数,则C++会自动合成一个复制构造函数,又称为浅复制构造函数. 2.深复制:如果使用指针或者系统资源(如数据库

python 字典深复制和浅复制

#!/usr/bin/python# -*- coding: UTF-8 -*- import copydict1 = {'user': 'vickey', 'num': [1, 2, 3],'age':{'a':'1','b':'2'}}dict2 = dict1 # 对原始数据的任何操作都会影响该复制# 先进行数据的浅复制和深复制操作dict3 = dict1.copy() # 浅复制: 一级为引用对象,二级为拷贝:原始数据的二级目录改变了,浅复制的数据的二级目录也会改变,但一级目录不变di

clone()方法、深复制和浅复制

clone方法 Java中没有明确提供指针的概念和用法,而实质上没个new语句返回的都是一个指针的引用,只不过在大部分情况下开发人员不需要关心如何去操作这个指针而已. 在实际编程中,经常会遇到从某个已有对象A创建出另一个与A具有相同状态的对象B,并且B的修改不会影响到A的情况,例如Prototype(原型)模式中,就需要clone一个对象实例. 仅仅通过简单的复制操作显然无法达到这个目的,而Java提供了一个简单有效的clone()方法来满足这个需求. Java中所有的类默认都继承自Object

实现 $.extend 的深复制和浅复制

$.extend 是jquery常用的一个方法,该方法通过传第一个布尔型参数可以指定为深复制还是浅复制,如何使用不在本文讨论. 先来理解下什么是深复制: var ob1 = {'name' : 'Jack' , 'child' : {'name' : 'Tom', 'age' : '7'}}; var ob2 = {'name' : 'Rose' , 'child' : {'name' : 'Mike'}}; 浅复制后的结果:{'name' : 'Jack' ,'child' : {'name'

iOS深复制和浅复制

1.copy关键字 1> 浅拷贝与深拷贝 浅拷贝就是对内存地址的复制,让目标对象指针和源对象指向同一片内存空间. 深拷贝是指拷贝对象的具体内容,而内存地址是自主分配的,拷贝结束之后,两个对象虽然存的值是相同的,但是内存地址不一样,两个对象也互不影响,互不干涉. 2> copy和mutableCopy copy:对于可变对象为深复制,引用计数不改变;对于不可变对象是浅复制,引用计数每次加一.始终返回一个不可变对象. mutableCopy:始终是深复制,引用计数不改变.始终返回一个可变对象. 3

(知其所以然 主题2)从底层分析OC中ARC和非ARC下深复制和浅复制

今天,在坊间听到有人在争论OC中关于NSString的深浅复制,听了下,感觉很有必要来一个分析总结,让我们从底层去了解OC中深浅复制的运作机制. 所谓copy就是在原有对象的基础上产生一个副本对象,遵循最关键的两点原则: 1. 改变原对象的属性和行为不会对副本对象产生任何影响 2. 改变副本对象的属性和行为不会对原对象产生任何影响 在理解了这一层之后,我们一起来研究下deep copy 和 shallow copy,因为苹果是一个非常注重性能的公司,所以拷贝在底层实现没那么简单: 以NSStri