接上文,在小陳合理的推廣下,小陳的鋪貨量也是愈來愈大,愈來愈多,訂單數量也是愈來愈多,大到上市公司,運動品牌專賣店,小到街邊飾品小店等都來向小陳這邊進貨,可是隨着訂單的愈來愈多,如今天天的訂單量都要將近10萬量的計數,這時候一件讓小陳頭疼的事情來了,由於訂單量過於多,如今小陳那邊的出單機的速率已經跟不上了,由於本來出單機是一單單的打出來的,可是由於訂單量過於龐大,速度實在跟不上了,並且小陳認真的觀察了一下,訂單的格式都是差很少的,都是訂單時間,訂單數量,訂單的產品信息,預約公司的信息,基本上都是信息都是大同小異,咱們先來看看街邊小店的訂單格式:java
1 public class OrderInfo { 2 private String shopName; 3 4 private String shopAddr; 5 6 private String shopMobile; 7 8 private String productName; 9 10 private String productNumber; 11 }//由於篇幅緣由,setter/getter方法就不寫了
街邊小店的訂單格式比較簡單,就基本信息和地址就是了,可是別看這種街邊小店,如今有將近3K家小店跟小陳的公司有合做,每月的營收可很多,有的時候小店的名字、地址、手機同樣,就產品和數量不同,又要從新生成一個訂單,有的是小店的開了分店,地址不同,可是其餘的信息又同樣,可是每一個訂單新生成的速度忒慢(若是每一個訂單都要生成,既浪費虛擬機的性能,並且每次填寫相同的信息也要花費不少時間),這個時候,小陳想既然都同樣,乾脆複製得了,而後再從新填上區別的信息,這樣就能夠一個訂單範本多家公司使用了。(你們能夠想一想爲何這裏不用工廠模式來生成訂單?)jvm
接下來咱們就來看看怎麼來進行復制:ide
1 public class OrderInfo implements Cloneable{ 2 private String shopName; 3 private String shopAddr; 4 private String shopMobile; 5 private String productName; 6 private String productNumber; 7 8 @Override 9 protected Object clone() { 10 try { 11 return super.clone(); 12 } catch (CloneNotSupportedException e) { 13 e.printStackTrace(); 14 } 15 return null; 16 } 17 }//由於篇幅緣由,setter/getter方法就不寫了
在這裏OrderInfo必須實現Cloneable,讓虛擬機知道該對象是可複製的,在這裏必須說明一點,clone對象不是Cloneable中的方法,若是咱們點進源代碼裏面看的話,會發現這個接口是個空接口,那這個clone方法是哪裏來的呢?Java裏面全部的對象都繼承自Object,因此clone方法是Object對象中的方法,咱們這裏是重寫了他的方法。好了,這樣的話,咱們來看看客戶端來怎麼生成,一家小店有兩家分店,除了地址其餘的信息都同樣的訂單了。性能
1 @Test 2 public void clien() { 3 OrderInfo orderInfo = new OrderInfo("飾品小店", "北京王府井大街", "13888888888", "騎士徽章", "10000"); 4 5 OrderInfo cloneInfo = (OrderInfo)orderInfo.clone(); 6 7 cloneInfo.setShopAddr("北京王府井大街2號"); 8 9 System.out.println(orderInfo); 10 System.out.println(cloneInfo); 11 }
OrderInfo [shopName=飾品小店, shopAddr=北京王府井大街, shopMobile=13888888888, productName=騎士徽章, productNumber=10000]
OrderInfo [shopName=飾品小店, shopAddr=北京王府井大街2號, shopMobile=13888888888, productName=騎士徽章, productNumber=10000]ui
這裏的話,咱們能夠看到除了店面的地址不同,其餘的信息所有同樣了,這樣子就省去了不少成本了,訂單的生產速度也快了不止一個級別,小陳很是開心,可是這個時候,訂單出單員小A發現了個問題了,當訂單是街邊小店的訂單的時候,訂單會沒有問題,可是當是上市公司的訂單,或者品牌大店的訂單的時候,出單就會有問題,小陳觀察了一下,原來上市集團的大單的訂單格式是下面這種方式的:this
1 public class OrderInfo implements Cloneable{ 2 private Product productInfo; 3 private Company company; 4 5 @Override 6 protected Object clone() { 7 try { 8 return super.clone(); 9 } catch (CloneNotSupportedException e) { 10 e.printStackTrace(); 11 } 12 return null; 13 } 14 } 15 16 class Product { 17 private String productName; 18 private String productBuildeAddr; 19 private String productBuildeDate; 20 //...等一系列關於產品的信息,由於篇幅略過 21 } 22 23 class Company { 24 private String companyName; 25 private String companyAddr; 26 private String companyMobile; 27 //...等一系列關於公司的信息,由於篇幅略過 28 }
大型公司的信息都比較完善,並且他們都把信息封裝到了一個個的對象中去了,訂單中展現出了一個個的對象,那爲何咱們clone的時候不起做用了呢?咱們再來看看客戶端的調用:spa
1 @Test 2 public void clien() { 3 OrderInfo orderInfo = new OrderInfo(new Product("騎士徽章","克利夫蘭","20160601"),new Company("騎士公司", "北京騎士大道", "13666666666")); 4 5 OrderInfo cloneInfo = (OrderInfo)orderInfo.clone(); 6 7 cloneInfo.getCompany().setCompanyAddr("北京騎士大道2號"); 8 9 System.out.println(orderInfo); 10 System.out.println(cloneInfo); 11 }
OrderInfo [productInfo=Product [productName=騎士徽章, productBuildeAddr=克利夫蘭, productBuildeDate=20160601], company=Company [companyName=騎士公司, companyAddr=北京騎士大道2號, companyMobile=13666666666]]
OrderInfo [productInfo=Product [productName=騎士徽章, productBuildeAddr=克利夫蘭, productBuildeDate=20160601], company=Company [companyName=騎士公司, companyAddr=北京騎士大道2號, companyMobile=13666666666]]code
咱們這裏就能夠看到了clone訂單更改了地址以後,原對象也更改了,這裏就涉及到了jvm虛擬中的對象的引用了。(說的簡單點就是,其實java中的每一個對象在jvm中算是一個引用,引用指向了堆中的對象,而咱們在克隆一個對象時,若是進行了淺拷貝的話,那只是將這個引用複製了一次,而沒有對這個對象進行克隆,因此會致使,對象的克隆失敗,由於兩個引用都指向了堆中的同一個對象,因此在這裏咱們就須要進行deep Clone),這裏的deep Clone有兩種方式:對象
一種就是對須要克隆的對象裏面的對象,所有實現clone的方法,那樣的話,clone的時候,他就會所有進行復制了,相似上文中的方法blog
1 class Product implements Cloneable{ 2 @Override 3 protected Object clone() { 4 try { 5 return super.clone(); 6 } catch (CloneNotSupportedException e) { 7 e.printStackTrace(); 8 } 9 return null; 10 } 11 } 12 13 class Company implements Cloneable{ 14 @Override 15 protected Object clone() { 16 try { 17 return super.clone(); 18 } catch (CloneNotSupportedException e) { 19 e.printStackTrace(); 20 } 21 return null; 22 } 23 }
這裏必須注意到的是,若是對象裏面還有對象的話,那就必須一直實現Cloneable。
接下來咱們重點介紹第二種方法:流式克隆
在流式克隆中,咱們這邊須要使用到Serializable這個接口,這個接口跟Cloneable同樣,也是標識接口,這個接口也是空方法,實現了該接口的對象被標識爲可序列化的
1 public class OrderInfo implements Cloneable,Serializable{ 2 private Product productInfo; 3 private Company company; 4 5 @Override 6 protected Object clone() { 7 try { 8 ByteArrayOutputStream baos = new ByteArrayOutputStream(); 9 ObjectOutputStream oos = new ObjectOutputStream(baos); 10 oos.writeObject(this); 11 ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray()); 12 ObjectInputStream ois = new ObjectInputStream(bais); 13 return ois.readObject(); 14 } catch (IOException e) { 15 e.printStackTrace(); 16 } catch (ClassNotFoundException e) { 17 e.printStackTrace(); 18 } 19 return null; 20 } 21 }
這裏對其進行IO操做是使用JVM中的將對象寫到流中是對象的一個拷貝的這一個特性,而源對象仍然保留在了jvm中,因此從新讀取出來的話又是一條好對象啦,可是這裏必須注意的是若是使用流式拷貝的話,那內部全部的被拷貝的對象都要實現Serializable這個接口,只須要實現Serializable接口便可,不須要其餘的操做。而後咱們再執行客戶端的操做就能夠看到,客戶端獲得的是兩個不一樣的對象了。
如今小陳又解決了一個問題了,如今訂單的問題也解決了,也再也不會被大量的訂單致使出貨慢,讓客戶投訴了,在創業的這段時間遇到了不一樣的問題,可是小陳有自信能夠一步步的解決掉,下回小陳還會遇到什麼樣的問題呢?
欲知下回如何,且聽下文分解。