实现cloneable接口,重写clone方法;注意,不重写的话也能够获取到对象,可是获取到的和发动建立的对象是同一个对象,即只是克隆了引用,hashCode是同样的java
public class Sheep implements Cloneable{ private String name; private int age; //getter、setter、构造器 .................. //重写克隆方法:调用的是父类默认的clone方法来拷贝sheep类 @Override protected Object clone(){ Object sheep = null; try { sheep = super.clone(); } catch (CloneNotSupportedException e) { // TODO Auto-generated catch block e.printStackTrace(); } // TODO Auto-generated method stub return sheep; } }
发动克隆spring
public class client { public static void main(String[] args) { Sheep sheep = new Sheep("Tom", 2); Sheep sheep2 = (Sheep)sheep.clone(); System.out.println(sheep.hashCode()); //366712642 System.out.println(sheep2.hashCode()); //1829164700 }
Spring中配置bean的时候,scope属性能够配置一个prototype值,该值指定该bean的建立是使用原型模式数组
在建立ioc容器后,经过getBean()获取bean对象时,往里追能够发如今核心方法处spring对bean的scope属性进行了判断,配置了prototype时,进入了原型模式的使用安全
建立ioc的时候建立了一个这样的容器实例
ide
该类中对getBean()方法的定义以下ui
public Object getBean(String name) throws BeansException { this.assertBeanFactoryActive(); //咱们先进入getBeanFactory()方法,看看获得的是哪一个BeanFactory,再寻找他的getBean()方法 return this.getBeanFactory().getBean(name); } //追踪发现这是一个抽象方法,应该是由AbstractApplicationContext的子类实现 public abstract ConfigurableListableBeanFactory getBeanFactory() throws IllegalStateException;
往下找getBeanFactory()方法的实现this
发如今AbstractRefreshableApplicationContext中实现了这个方法,返回的是一个DefaultListableBeanFactory,也就是调用了DefaultListableBeanFactory的getBean()方法prototype
private DefaultListableBeanFactory beanFactory; //实现了getBeanFactory方法,确保了线程安全的前提下返回了一个DefaultListableBeanFactory public final ConfigurableListableBeanFactory getBeanFactory() { synchronized(this.beanFactoryMonitor) { if (this.beanFactory == null) { throw new IllegalStateException("BeanFactory not initialized or already closed - call 'refresh' before accessing beans via the ApplicationContext"); } else { return this.beanFactory; } } }
去到DefaultListableBeanFactory中没有找到getBean()方法,因而往他的父类去找线程
从这个bean的父类的父类AbstractBeanFactory能够看到这个getBean(),同时调用了核心方法doGetBean();3d
public Object getBean(String name) throws BeansException { return this.doGetBean(name, (Class)null, (Object[])null, false); }
进入到doGetBean()方法能够发现,spring对参数进行了判断,对应建立了原型模式的对象
protected <T> T doGetBean(String name, @Nullable Class<T> requiredType, @Nullable Object[] args, boolean typeCheckOnly) throws BeansException { String beanName = this.transformedBeanName(name); Object sharedInstance = this.getSingleton(beanName); ................. if (mbd.isSingleton()) { sharedInstance = this.getSingleton(beanName, () -> { try { return this.createBean(beanName, mbd, args); } catch (BeansException var5) { this.destroySingleton(beanName); throw var5; } }); bean = this.getObjectForBeanInstance(sharedInstance, name, beanName, mbd); //判断了是否设置了原型模式 } else if (mbd.isPrototype()) { var11 = null; Object prototypeInstance; try { this.beforePrototypeCreation(beanName); //进入了原型模式的对象建立 prototypeInstance = this.createBean(beanName, mbd, args); } finally { this.afterPrototypeCreation(beanName); } bean = this.getObjectForBeanInstance(prototypeInstance, name, beanName, mbd); } else { ...................
同时能够发现AbstractBeanFactory也是BeanFactory的实现类
对于数据类型是基本数据类型的成员变量,浅拷贝会直接进行值传递,也就是将该属性值复制一份给新的对象属性
对于数据类型是引用类型的成员变量(对象、数组等),浅拷贝会进行引用传递,即将该成员变量实例的引用地址复制到新的对象属性中,新对象属性中的成员变量所指向的仍是和原型成员变量所指向的是同一个实例,在一个对象中修改为员变量会影响到其它对象中的成员变量
浅拷贝就是使用Object默认的clone()来实现的
复制全部基本类型的成员变量值
为全部引用数据类型的变量申请存储空间,并复制每一个引用数据类型成员变量所引用的对象,也就是说,对象进行深拷贝要对整个对象进行拷贝
实现方式
重写clone方法来实现深拷贝
public class DeepCloneableTarget implements Serializable,Cloneable{ private static final long serialVersionUID= 1L; private String cloneName; private String cloneClass; ....................... } public class DeepPrototype implements Cloneable{ private String name; private DeepCloneableTarget deepCloneableTarget;//引用类型 public DeepPrototype() { // TODO Auto-generated constructor stub super(); } //深拷贝:方式一:重写clone() @Override protected Object clone() throws CloneNotSupportedException { // TODO Auto-generated method stub Object deep = null; DeepPrototype deepPrototype = (DeepPrototype)deep; deepPrototype.deepCloneableTarget = (DeepCloneableTarget)deepCloneableTarget.clone(); return deepPrototype; }
这个方法不推荐,当有多个引用数据类型时,代码量特别多,并且复杂
经过对象序列化l实现深拷贝(拷贝的类继承Serializable,还有内部成员变量时对象的类也要继承Serializable)
//深拷贝:方式二:经过对象的序列化实现 public Object deepClone() { //建立流 ByteArrayOutputStream bos = null; ObjectOutputStream oos = null; ByteArrayInputStream bis =null; ObjectInputStream ois = null; try { //序列化 bos = new ByteArrayOutputStream(); oos = new ObjectOutputStream(bos); oos.writeObject(this);//当前的对象以流的方式输出 //反序列化 bis = new ByteArrayInputStream(bos.toByteArray()); ois = new ObjectInputStream(bis); DeepPrototype deepPrototype = (DeepPrototype)ois.readObject(); return deepPrototype; } catch (Exception e) { // TODO: handle exception e.printStackTrace(); return null; }finally { try { bos.close(); oos.close(); bis.close(); ois.close(); } catch (Exception e2) { // TODO: handle exception } } }
推荐使用该方法,由于该方法直接将整个对象进行流操做,将整个对象序列输出,再反序列输入,就会自动拷贝一个对象,缺陷在于流操做效率较低,并且基本数据类型也要进行流操做。