美文网首页
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