JAVA学习之对象克隆

对象克隆

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());
      } 
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值