實現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 } } }
推薦使用該方法,由於該方法直接將整個對象進行流操做,將整個對象序列輸出,再反序列輸入,就會自動拷貝一個對象,缺陷在於流操做效率較低,並且基本數據類型也要進行流操做。