对象克隆的学习

在Java中所有的类都是缺省的继承自Java语言包中的Object类的,查看它的源码

native方法是非Java语言实现的代码,供Java程序调用的,因为Java程序是运行在JVM虚拟机上面
的,要想访问到比较底层的与操作系统相关的就没办法了,只能由靠近操作系统的语言来实现。

克隆的对象可能包含一些已经修改过的属性,而new出来的对象的属性都还是初始化时候的值,所以当需要一个新的对象来保存当前对象的状态就靠clone方法。那么把这个对象的临时属性一个一个的赋值给新new的对象不也行嘛?可以是可以,但是一来麻烦不说,通过上面的源码都发现了clone是一个native方法,在底层实现的。
常见的Object a=new Object();Object b;b=a;这种形式的代码复制的是引用,即对象在内存中的地址,a和b对象仍然指向了同一个对象。而通过clone方法赋值的对象跟原来的对象时同时独立存在的。

两种不同的克隆方法,浅克隆ShallowClone和深克隆DeepClone。浅克隆和深克隆的主要区别在于是否支持引用类型的成员变量的复制

浅克隆

1. 被复制的类需要实现Clonenable接口(不实现的话在调用clone方法会抛出
CloneNotSupportedException异常), 该接口为标记接口,不含任何方法
2. 覆盖clone()方法,访问修饰符设为public。方法中调用super.clone()方法得到需要的复制对象。
native为本地方法

public class Student implements Cloneable{
private int number;
public int getNumber() {
return number;
}
public void setNumber(int number) {
this.number = number;
}
@Override
public Object clone() {
Student stu = null;
try{
stu = (Student)super.clone();
}catch(CloneNotSupportedException e) {
e.printStackTrace();
}
return stu;
}
}

调用

Student stu1 = new Student();
stu1.setNumber(12345);
Student stu2 = (Student)stu1.clone();

在浅克隆中,如果原型对象的成员变量是值类型,将复制一份给克隆对象;如果原型对象的成员变量是引用类型,则将引用对象的地址复制一份给克隆对象,也就是说原型对象和克隆对象的成员变量指向相同的内存地址。
简单来说,在浅克隆中,当对象被复制时只复制它本身和其中包含的值类型的成员变量,而引用类型的成员对象并没有复制。

深克隆

在深克隆中,无论原型对象的成员变量是值类型还是引用类型,都将复制一份给克隆对象,深克隆将原型对象的所有引用对象也复制一份给克隆对象。
简单来说,在深克隆中,除了对象本身被复制外,对象所包含的所有成员变量也将复制。
在Java语言中,如果需要实现深克隆,可以通过覆盖Object类的clone()方法实现,也可以通过序列化Serialization等方式来实现。一般使用序列化的方式实现

序列化就是将对象写到流的过程,写到流中的对象是原有对象的一个拷贝,而原对象仍然存在于内存中。通过序列化实现的拷贝不仅可以复制对象本身,而且可以复制其引用的成员对象,因此通过序列化将对象写到一个流中,再从流里将其读出来,可以实现深克隆。需要注意的是能够实现序列化的对象其类必须实现Serializable接口,否则无法实现序列化操作。

原型模式

原型模式Prototype Pattern是用于创建重复的对象,同时又能保证性能。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。
这种模式是实现了一个原型接口,该接口用于创建当前对象的克隆。当直接创建对象的代价比较大时,则采用这种模式
意图:用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象。
优点:1、性能提高。 2、逃避构造函数的约束。
缺点:1、配备克隆方法需要对类的功能进行通盘考虑,这对于全新的类不是很难,但对于已有的类不一定很容易,特别当一个类引用不支持串行化的间接对象,或者引用含有循环结构的时候。 2、必须实现Cloneable接口。
注意:与通过对一个类进行实例化来构造新对象不同的是,原型模式是通过拷贝一个现有对象生成新对象的。浅拷贝实现 Cloneable,重写,深拷贝是通过实现 Serializable 读取二进制流。

抽象类定义

public abstract class Shape implements Cloneable {
private String id;
protected String type;
abstract void draw();
public String getType(){
return type;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public Object clone() {
Object clone = null;
try {
clone = super.clone();
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
return clone;
}
}

扩展抽象类的实体类

public class Rectangle extends Shape {
public Rectangle(){
type = "Rectangle";
}
@Override
public void draw() {
System.out.println("Inside Rectangle::draw() method.");
}
}

创建一个类获取实体类,并把它们存储在一个 Hashtable 中

public class ShapeCache {
private static Hashtable<String, Shape> shapeMap = new Hashtable<String,
Shape>();
public static Shape getShape(String shapeId) {
Shape cachedShape = shapeMap.get(shapeId);
return (Shape) cachedShape.clone();
}
// 对每种形状都运行操作创建该形状shapeMap.put(shapeKey, shape);
public static void loadCache() {
Circle circle = new Circle();
circle.setId("1");
shapeMap.put(circle.getId(),circle);
}
}

使用ShapeCache类来获取存储在Hashtable中的形状的克隆

public class PrototypePatternDemo {
public static void main(String[] args) {
ShapeCache.loadCache();
Shape clonedShape = (Shape) ShapeCache.getShape("1");
System.out.println("Shape : " + clonedShape.getType());
}
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值