<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    人在江湖

      BlogJava :: 首頁 :: 聯系 :: 聚合  :: 管理
      82 Posts :: 10 Stories :: 169 Comments :: 0 Trackbacks

    這篇包含三篇文章的轉載和摘抄一段effective java的code

    第一篇轉載

    大家都知道Serializable是一個mark interface,告訴JVM這個對象可以被轉換成二進制流來傳輸.
    但是Serializable與Externalizable的轉換二進制流的過程是不一樣的.
    Serializable 在我們實現這個接口的時候,我們可以使用4個私有方法來控制序列化的過程:
      我們來看一個例子:

    Java代碼

       1: public class FooImpl implements java.io.Serializable{   
       2: private String message;   
       3:  
       4: public String getFoo() {           
       5: return message;   
       6: }   
       7:  
       8: public void setMessage(String message) {   
       9: this.message = message;   
      10: }   
      11:  
      12: private void writeObject(java.io.ObjectOutputStream out) throws IOException {   
      13:     System.out.println("writeObject invoked");   
      14:     out.writeObject(this.message == null ? "hohohahaha" : this.message);   
      15: }   
      16:  
      17: private void readObject(java.io.ObjectInputStream in) throws IOException,   
      18:         ClassNotFoundException {   
      19:     System.out.println("readObject invoked");   
      20: this.message = (String) in.readObject();   
      21:     System.out.println("got message:" + message);   
      22: }   
      23:  
      24: private Object writeReplace() throws ObjectStreamException {   
      25:     System.out.println("writeReplace invoked");   
      26: return this;   
      27: }   
      28:  
      29: private Object readResolve() throws ObjectStreamException {   
      30:     System.out.println("readResolve invoked");   
      31: return this;   
      32: }   
      33:  
      34: public Object serialize() throws IOException, ClassNotFoundException {   
      35:     ByteArrayOutputStream baos = new ByteArrayOutputStream();   
      36:     ObjectOutputStream oos = new ObjectOutputStream(baos);   
      37:     oos.writeObject(this);   
      38:     ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());   
      39:     ObjectInputStream ois = new ObjectInputStream(bais);   
      40: return ois.readObject();   
      41: }   
      42: public static void main(String[] args) throws IOException,    
      43:              ClassNotFoundException {   
      44:                  FooImpl fooimpl = new FooImpl();   
      45:                  fooimpl.serialize();   
      46: }  

    我們運行這段代碼看到的debug信息:
    writeReplace invoked
    writeObject invoked
    readObject invoked
    readResolve invoked
    當進行序列化的時候:
    首先JVM會先調用writeReplace方法,在這個階段,我們可以進行張冠李戴,將需要進行序列化的對象換成我們指定的對象.
    跟著JVM將調用writeObject方法,來將對象中的屬性一個個進行序列化,我們可以在這個方法中控制住哪些屬性需要序列化.
    當反序列化的時候:
    JVM會調用readObject方法,將我們剛剛在writeObject方法序列化好的屬性,反序列化回來.
    然后在readResolve方法中,我們也可以指定JVM返回我們特定的對象(不是剛剛序列化回來的對象).
    注意到在writeReplace和readResolve,我們可以嚴格控制singleton的對象,在同一個JVM中完完全全只有唯一的對象,控制不讓singleton對象產生副本.
    Externalizable 是一個有實際方法需要實現的interface,包括writeExternal和readExternal:

    Java代碼

       1: public class FooImpl implements java.io.Externalizable {   
       2: private String message;   
       3:  
       4: public String getFoo() {   
       5: return message;   
       6:     }   
       7:  
       8: public void setMessage(String message) {   
       9: this.message = message;   
      10:     }   
      11:  
      12: private Object writeReplace() throws ObjectStreamException {   
      13:         System.out.println("writeReplace invoked");   
      14: return this;   
      15:     }   
      16:  
      17: private Object readResolve() throws ObjectStreamException {   
      18:         System.out.println("readResolve invoked");   
      19: return this;   
      20:     }   
      21:  
      22: public Object serialize() throws IOException, ClassNotFoundException {   
      23:         ByteArrayOutputStream baos = new ByteArrayOutputStream();   
      24:         ObjectOutputStream oos = new ObjectOutputStream(baos);   
      25:         oos.writeObject(this);   
      26:         ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());   
      27:         ObjectInputStream ois = new ObjectInputStream(bais);   
      28: return ois.readObject();   
      29:     }   
      30:  
      31: public void readExternal(ObjectInput arg0) throws IOException,   
      32:             ClassNotFoundException {   
      33:         System.out.println("readExternal invoked");   
      34:         Object obj = arg0.readObject();        
      35:     }   
      36:  
      37: public void writeExternal(ObjectOutput arg0) throws IOException {   
      38:         System.out.println("writeExternal invoked");   
      39:         arg0.writeObject("Hello world");   
      40:     }   
      41: public static void main(String[] args) throws IOException,    
      42:               ClassNotFoundException {   
      43:                   FooImpl fooimpl = new FooImpl();   
      44:                   fooimpl.serialize();   
      45:     }   
      46: }  

    我們運行這段代碼看到的debug信息:
    writeReplace invoked
    writeExternal invoked
    readExternal invoked
    readResolve invoked
    在此writeExternal 和readExternal 的作用與writeObject和readObject 一樣.
    最后,當我們同時實現了兩個interface的時候,JVM只運行Externalizable 接口里面的writeExternal 和readExternal 方法對序列化內容進行處理.
    需要注意的是:Serializable是一個真正的mark interface,writeObject,readObject, writeReplace,readResolve是直接與JVM通信,告訴JVM序列化的內容.

     

    第二篇轉載

    1) 實現了Serializable接口的類的改動變得很難(兼容性問題)。
        如果你想保持向下兼容性的話,這意味著要求新版本反序列化老版本序列化的數據流;如果你想保持向上兼容性的話,這意味著要求老版本反序列化新版本的數據流。
        尤其是向下兼容性的問題帶來了讓我們的代碼實現很難改動的問題,為了能在新版本中反序列化老版本的數據流,類的實現必須要保留老版本的實現過程。這無疑是我們給自己加帶上的一副枷鎖。

    2) 實現了Serializable接口的類的測試成本大大增加了可以想象,當新版本發布時,為了保持兼容性,你的測試量將是版本數的平方!

    3) 草率的接受默認的序列化方式可能會帶來性能問題,甚至更糟。

    4) 序列化作為額外的一種“構造函數”可能破壞數據的完整性、約束性,甚至,一個精心偽造的數據流所序列化出的對象可能帶來安全隱患。

    當一個父類實現Serializable接口后,他的子類都將自動的實現序列化。

    1. 當序列化遇到繼承時引發的問題?
        序列化類的所有子類本身都是可序列化的。但是,如果父類是非序列化的,要求子類是可序列化的,該怎么辦呢?
        "To allow subtypes of non-serializable classes to be serialized, the subtype may assume responsibility for saving and restoring the state of the supertype's public, protected, and (if accessible) package fields. The subtype may assume this responsibility only if the class it extends has an accessible no-arg constructor to initialize the class's state. It is an error to declare a class Serializable if this is not the case. The error will be detected at runtime. "(允許非序列化類的子類型序列化,僅當該類的擴展子類有一個可訪問的無參數的構造函數用來初始化該類的狀態時,其子類可以負責保存和恢復父類型的公有 的、保護的和(如果可訪問)包的域的狀態。否則的話聲明其子類是可序列化的將會發生錯誤,該錯誤在運行的時候被檢測)

    也就是說,要為一個沒有實現Serializable接口的父類,編寫一個能夠序列化的子類要做兩件事情:
    其一,父類要有一個無參的constructor。

       1: public class ParentClass {
       2:     int parentValue;
       3:     public ParentClass();       //如果要求其子類可以序列化,該無參數構造函數是必須的
       4:     public ParentClass(int parentValue) {
       5:         this.parentValue = parentValue;
       6:     }
       7:     public String toString() {
       8:         return "Parent Value:" + parentValue;
       9:     }
      10: }

    其二,子類要負責序列化(反序列化)父類的域。
    子 類序列化父類域可以通過自定義序列化實現。自定義序列化要求類中必須有writeObject和readObject方法,它們的定義必須是如下形 式,writeObject方法中必須首先調用ObjectOutputStream類的defaultWriteObject方法處理默認的序列化,其 它的序列化在其后進行處理;readObject方法讀取的順序必須和寫入的順序一樣,即首先通過objectInputStream的 defaultReadObject方法讀取默認的序列化,再依次讀出其它的自定義序列化信息。

       1: private void writeObject(ObjectOutputStream s) throws IOException {
       2:     s.defaultWriteObject();
       3:     // customized serialization code
       4: }
       5:  
       6: private void readObject(ObjectInputStream s) throws IOException  {
       7:     s.defaultReadObject();
       8:     // customized deserialization code
       9:     // followed by code to update the object, if necessary
      10: }
      11: 如果可序列化類中包含正確的writeObject/readObject函數對,進行序列化和反序列化的時候,writeObject/readObject就會被調用,以代替默認的序列化行為
      12: public class ChildClass Extends ParantClass implements Serializable {
      13:     int subvalue;
      14:     public ChildClass(int supervalue,int subvalue) {
      15:         super(supervalue);
      16:         this.subvalue=subvalue;
      17:     }
      18:  
      19:     public String toString() {
      20:         return super.toString()+" sub: "+subvalue;
      21:     }
      22:  
      23:     private void writeObject(java.io.ObjectOutputStream out) throws IOException{
      24:         out.defaultWriteObject();//先序列化對象
      25:         out.writeInt(supervalue);//再序列化父類的域
      26:     }
      27:  
      28:     private void readObject(java.io.ObjectInputStream in) throws IOException, ClassNotFoundException{
      29:         in.defaultReadObject();//先反序列化對象
      30:         supervalue=in.readInt();//再反序列化父類的域
      31:     }
      32: }
      33:  

    2. 何時接受默認的java序列化?
        java默認的序列化行為,java將一切關于對象的信息都保存了下了,也就是說,有些時候那些不需要保存的也被保存了下來。一般情況下,我們僅僅需要保存邏輯數據就可以了。不需要保存的數據我們可以用關鍵字transient標出。
    以下是一個例子:

       1: import java.io.*;
       2: public class Serial implements Serializable {
       3:     int company_id;
       4:     String company_addr;
       5:     transient boolean company_flag;
       6: }

        則company_flag字段將不會參與序列化與反序列化,但同時也增加了為它初始值的責任。這也是序列化常常導致的問題之一。因為序列化相當于一個只 接受數據流的public構造函數,這種對象構造方法是語言之外的。但他仍然是一種形式上的構造函數。如若你的類不能夠通過其他方面來保證初始化,則你需 要額外的提供readObject方法,首先正常的反序列化,然后對transient標示的字段進行初始化。

     

    第三篇轉載

    Serialization is a handy and powerful aspect of Java. Being able to persist objects onto disk and read them later is one of the most under-used features of Java I think. In the base cases, serialization can 'just work'. However, as more complicated object formats and design patterns are adopted, the likelihood that 'transparent' object serialization will 'just work' becomes less and less likely. One case where serialization needs a little help is when dealing with a controlled set of instances - such as singletons and enumerations.

    Whenever a singleton is serializable, it's important to ensure that the singleton instance is used. This is done through the readResolve method. For instance, a singleton may look like this:

       1: public final class MySingleton {
       2: private MySingleton() { }
       3: private static final MySingleton INSTANCE = new MySingleton();
       4: public static MySingleton getInstance() { return INSTANCE; }
       5: }

    In the above example, there is only one way to get an instance of MySingleton - that is to use the getInstance() method. Unfortunately, this code becomes 'broken' simply by adding one interface implementation:

    public final class MySingleton implements Serializable {
    //...

    Now through the serializable tools, someone can write a singleton instance to disk, and then read it back up, effectively getting a new instance. Even though the constructor is private, the serializable tools have special access to create instances of a class regardless. Serialization has a special hook it uses - a private method on the class being instantiated called readResolve() - which is meant to supply a 'hook' for a class developer to ensure that they have a say in what object is returned by serialization. Oddly enough, readResolve() is not static, but is instead invoked on the new instance just created by the serialization. We'll get into that in a minute - for now, here is how our readResolve() method works with our singleton:

       1: public final class MySingleton {
       2: private MySingleton() { }
       3: private static final MySingleton INSTANCE = new MySingleton();
       4: public static MySingleton getInstance() { return INSTANCE; }
       5: private Object readResolve() throws ObjectStreamException {
       6: // instead of the object we're on,
       7: // return the class variable INSTANCE
       8: return INSTANCE;
       9: }
      10: }

    So far so good. Things get a little complicated when dealing with more than one instance however. To explain this, I'll show this using a type-safe enumeration. Keep in mind that Java 5's enum type automatically handles this readResolve case for you. Here is a nice little enumeration:

       1: public final class Sides {
       2: private int value;
       3: private Sides(int newVal) { value = newVal; }
       4: private static final int LEFT_VALUE = 1;
       5: private static final int RIGHT_VALUE = 2;
       6: private static final int TOP_VALUE = 3;
       7: private static final int BOTTOM_VALUE = 4;
       8: public static final LEFT = new Sides(LEFT_VALUE);
       9: public static final RIGHT = new Sides(RIGHT_VALUE);
      10: public static final TOP = new Sides(TOP_VALUE);
      11: public static final BOTTOM = new Sides(BOTTOM_VALUE);
      12: }

    Now, implementing serialization, the key to determining which instance to return is in inspecting what value is set on the object itself:

       1: public final class Sides implements Serializable {
       2: private int value;
       3: private Sides(int newVal) { value = newVal; }
       4: private static final int LEFT_VALUE = 1;
       5: private static final int RIGHT_VALUE = 2;
       6: private static final int TOP_VALUE = 3;
       7: private static final int BOTTOM_VALUE = 4;
       8: public static final LEFT = new Sides(LEFT_VALUE);
       9: public static final RIGHT = new Sides(RIGHT_VALUE);
      10: public static final TOP = new Sides(TOP_VALUE);
      11: public static final BOTTOM = new Sides(BOTTOM_VALUE);
      12: private Object readResolve() throws ObjectStreamException {
      13: // Switch on this instance's value to figure out which class variable
      14: // this is meant to match
      15: switch(value) {
      16: case LEFT_VALUE: return LEFT;
      17: case RIGHT_VALUE: return RIGHT;
      18: case TOP_VALUE: return TOP;
      19: case BOTTOM_VALUE: return BOTTOM;
      20: }
      21: return null;
      22: }
      23: }

     

    自己的微小筆記

    1. serialVersionUID: 如果新的class要兼容舊的,這個id必須是一樣的。 自己不寫這個field, 在runtime的時候會自動生成
    2. effective java里custom serialization的一個例子:

       1: // StringList with a reasonable custom serialized form
       2: public final class StringList implements Serializable {
       3: private transient int size = 0;
       4: private transient Entry head = null;
       5: // No longer Serializable!
       6: private static class Entry {
       7: String data;
       8: Entry next;
       9: Entry previous;
      10: }
      11: // Appends the specified string to the list
      12: public final void add(String s) { ... }
      13: /**
      14: * Serialize this {@code StringList} instance.
      15: *
      16: * @serialData The size of the list (the number of strings
      17: * it contains) is emitted ({@code int}), followed by all of
      18: * its elements (each a {@code String}), in the proper
      19: * sequence.
      20: */
      21: private void writeObject(ObjectOutputStream s)
      22: throws IOException {
      23: s.defaultWriteObject();
      24: s.writeInt(size);
      25: // Write out all elements in the proper order.
      26: for (Entry e = head; e != null; e = e.next)
      27: s.writeObject(e.data);
      28: }
      29: private void readObject(ObjectInputStream s)
      30: throws IOException, ClassNotFoundException {
      31: s.defaultReadObject();
      32: int numElements = s.readInt();
      33: // Read in all elements and insert them in list
      34: for (int i = 0; i < numElements; i++)
      35: add((String) s.readObject());
      36: }
      37: ... // Remainder omitted
      38: }
    posted on 2011-02-23 23:15 人在江湖 閱讀(1152) 評論(0)  編輯  收藏 所屬分類: java
    主站蜘蛛池模板: 亚洲日韩精品无码专区加勒比☆ | 免费很黄很色裸乳在线观看| 日韩免费一区二区三区| 免费看一级做a爰片久久| 伊人久久大香线蕉亚洲| 内射少妇36P亚洲区| 亚洲一卡2卡3卡4卡乱码 在线 | 一区二区三区在线免费 | 免费一级毛片在线播放视频免费观看永久| 免费的黄色的网站| 久久er国产精品免费观看2| 中文字幕免费在线看线人| 国产色爽免费视频| 亚洲综合AV在线在线播放| 亚洲国产成人超福利久久精品| 亚洲国产欧洲综合997久久| 久久久久久毛片免费看| 国产电影午夜成年免费视频| 国产伦一区二区三区免费| 亚洲成av人片在线观看无码不卡| 亚洲午夜精品在线| 人碰人碰人成人免费视频| 99久久精品国产免费| 国产免费怕怕免费视频观看| 亚洲AV无码久久精品成人| 亚洲日韩国产一区二区三区在线| 国产精品偷伦视频免费观看了| 免费看男女下面日出水来| 亚洲一区二区三区无码影院| 亚洲国产成人久久三区| 免费一级毛suv好看的国产网站 | 四虎影视无码永久免费| 亚洲第一成年免费网站| 国产午夜亚洲精品国产成人小说| 亚洲欧洲日产v特级毛片| 一级毛片在播放免费| 成人免费无码大片a毛片| 亚洲免费在线视频| 人成免费在线视频| 女人张开腿等男人桶免费视频| 亚洲高清专区日韩精品|