美文网首页
Externalizable和Serializable

Externalizable和Serializable

作者: Cter | 来源:发表于2018-01-30 14:00 被阅读5次

    1、Serializable序列化时不会调用默认的构造器,而Externalizable序列化时会调用默认构造器的!!! 

    2、Serializable:一个对象想要被序列化,那么它的类就要实现 此接口,这个对象的所有属性(包括private属性、包括其引用的对象)都可以被序列化和反序列化来保存、传递。 

    Externalizable:他是Serializable接口的子类,有时我们不希望序列化那么多,可以使用这个接口,这个接口的writeExternal()和readExternal()方法可以指定序列化哪些属性。

    注意: 

    对象的序列化并不属于新的Reader和Writer层次结构的一部分,而是沿用老式的InputStream和OutputStream结构,在某些情况下,不得不混合使用两种类型的层次结构。

    恢复了一个反序列化的对象后,如果想对其做更多的事情(对象.getClass().xxx),必须保证JVM能在本地类路径或者因特网的其他什么地方找到相关的.class文件。 

    恢复对象的默认构建器必须是public的,否则会抛异常。

    由于Externalizable对象默认时不保存对象的任何字段,所以transient关键字只能伴随Serializable使用,虽然Externalizable对象中使用transient关键字也不报错,但不起任何作用。 

    3、把transient修饰的字段序列化。这也可以?of course!!

    import java.io.*;import java.util.*;public classSerialCtlimplementsSerializable{ String a;

            transient String b;

            public SerialCtl(String aa, String bb){

                    a="Not Transient:"+aa;

                    b="Transient:"+bb;

            }

            public String toString(){

                    return a+"\n"+b;

            }

            private void writeObject(ObjectOutputStream o)throws IOException{

                    o.defaultWriteObject();

                    o.writeObject(b);

            }

            private void readObject(ObjectInputStream streamr)throws IOException, ClassNotFoundException{

                    streamr.defaultReadObject();

                    b=(String)streamr.readObject();

            }

            public static void main(String[] args){

                    SerialCtl sc =

                            new SerialCtl("Test1","Test2");

                    System.out.println("Before:\n"+sc);

                    ByteArrayOutputStream buf =

                            new ByteArrayOutputStream();

                    try{

                            ObjectOutputStream out1 = new                                ObjectOutputStream(buf);

                            out1.writeObject(sc);

                            ObjectInputStream in1 = new                                ObjectInputStream(new                                        ByteArrayInputStream(buf.toByteArray()));

                            SerialCtl sc2 = (SerialCtl)in1.readObject();

                            System.out.println("After:\n"+sc2);

                    }catch(ClassNotFoundException e){

                            e.printStackTrace();

                    }catch(IOException e){

                            e.printStackTrace();

                    }

            }

    }

    我们看下输出结果就知道了:

    虽然 String b被transient修饰了,但是b仍然被序列化了。 

    假如代码稍作修改,transient又起作用了

    importjava.io.*;importjava.util.*;publicclassSerialCtlimplementsSerializable{String a;transientString b;publicSerialCtl(String aa, String bb){                a="Not Transient:"+aa;                b="Transient:"+bb;        }publicStringtoString(){returna+"\n"+b;        }privatevoidwriteObject(ObjectOutputStream o)throwsIOException{                o.defaultWriteObject();//      o.writeObject(b);}privatevoidreadObject(ObjectInputStream streamr)throwsIOException, ClassNotFoundException{                streamr.defaultReadObject();//      b=(String)streamr.readObject();}publicstaticvoidmain(String[] args){                SerialCtl sc =newSerialCtl("Test1","Test2");                System.out.println("Before:\n"+sc);                ByteArrayOutputStream buf =newByteArrayOutputStream();try{                        ObjectOutputStream out1 =newObjectOutputStream(buf);                        out1.writeObject(sc);                        ObjectInputStream in1 =newObjectInputStream(newByteArrayInputStream(buf.toByteArray()));                        SerialCtl sc2 = (SerialCtl)in1.readObject();                        System.out.println("After:\n"+sc2);                }catch(ClassNotFoundException e){                        e.printStackTrace();                }catch(IOException e){                        e.printStackTrace();                }        }}

    1

    2

    3

    4

    5

    6

    7

    8

    9

    10

    11

    12

    13

    14

    15

    16

    17

    18

    19

    20

    21

    22

    23

    24

    25

    26

    27

    28

    29

    30

    31

    32

    33

    34

    35

    36

    37

    38

    39

    40

    41

    42

    43

    44

    45

    46

    47

    48

    49

    50

    51

    结果:

    方法writeObject处理对象的序列化。如果声明该方法,它将会被ObjectOutputStream调用而不是默认的序列化进程。如果你是第一次看见它,你会很惊奇尽管它们被外部类调用但事实上这是两个private的方法。并且它们既不存在于java.lang.Object,也没有在Serializable中声明。那么ObjectOutputStream如何使用它们的呢?这个吗,ObjectOutputStream使用了反射来寻找是否声明了这两个方法。因为ObjectOutputStream使用getPrivateMethod(通过getDeclareMethod可以获得私有方法),所以这些方法不得不被声明为private以至于供ObjectOutputStream来使用。 

    在两个方法的开始处,你会发现调用了defaultWriteObject()和defaultReadObject()。它们做的是默认的序列化进程,就像写/读所有的non-transient和 non-static字段(但他们不会去做serialVersionUID的检查).通常说来,所有我们想要自己处理的字段都应该声明为transient。这样的话,defaultWriteObject/defaultReadObject便可以专注于其余字段,而我们则可为这些特定的字段(译者:指transient)定制序列化。使用那两个默认的方法并不是强制的,而是给予了处理复杂应用时更多的灵活性。

    相关文章

      网友评论

          本文标题:Externalizable和Serializable

          本文链接:https://www.haomeiwen.com/subject/lxcczxtx.html