序列化学习Serializable

在学习集合的途中,遇到了序列化的问题,就是

public class ArrayList<E> extends AbstractList<E>
        implements List<E>, RandomAccess, Cloneable, java.io.Serializable
{
    private static final long serialVersionUID = 8683452581122892189L;

    /**
     * The array buffer into which the elements of the ArrayList are stored.
     * The capacity of the ArrayList is the length of this array buffer.
     */
    private transient Object[] elementData;

    /**
     * The size of the ArrayList (the number of elements it contains).
     *
     * @serial
     */
    private int size;

这个transient关键字。没了解过。

1.序列化的定义

   Java平台允许我们在内存中创建可复用的Java对象,但一般情况下,只有当JVM处于运行时,这些对象才可能存在,即,这些对象的生命周期不会比JVM的生命周期更长。但在现实应用中,就可能要求在JVM停止运行之后能够保存(持久化)指定的对象,并在将来重新读取被保存的对象。Java对象序列化就能够帮助我们实现该功能。
    使用Java对象序列化,在保存对象时,会把其状态保存为一组字节,在未来,再将这些字节组装成对象。必须注意地是,对象序列化保存的是对象的"状态",即它的成员变量。由此可知,对象序列化不会关注类中的静态变量。
    除了在持久化对象时会用到对象序列化之外,当使用RMI(远程方法调用),或在网络中传递对象时,都会用到对象序列化。

 

2.如何使用

  在Java中,只要一个类实现了java.io.Serializable接口,那么它就可以被序列化。此处将创建一个可序列化的类Person,一个枚举类Gender。

  Gender:

public enum Gender {
    MALE,FEMALE
}

  Person:

public class Person implements Serializable {
        private String name = null;
        private Integer age = null;
        private Gender gender = null;
        transient private String like = null;
        public Person(String name, Integer age, Gender gender,String like) {
            System.out.println("arg constructor");
            this.name = name;
            this.age = age;
            this.gender = gender;
            this.like = like;
        }
        public Person() {
            System.out.println("non-arg constructor");
        }
        public String getName() {
            return name;
        }
        public void setName(String name) {
            this.name = name;
        }
        public Integer getAge() {
            return age;
        }
        public void setAge(Integer age) {
            this.age = age;
        }
        public Gender getGender() {
            return gender;
        }
        public void setGender(Gender gender) {
            this.gender = gender;
        }
        @Override
        public String toString() {
            return "Person [name=" + name + ", age=" + age + ", gender="
                    + gender + "," + like + "]";
        }     
}

 

Gender枚举类,表示性别。

Person类,实现了Serializable接口,它包含四个字段:name,String类型;age,Integer类型;gender,Gender类型;like,String类型。另外,还重写该类的toString()方法,以方便打印Person实例中的内容。而like是被transient修饰。

这里写一个序列化程序:

  

public class SimpleSerial {
        public static void main(String[] args) throws IOException, ClassNotFoundException {
            File file = new File("Person.out");
            ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(file));
            Person  p  = new Person("tony",23,Gender.MALE,"play game");
            oos.writeObject(p);
            oos.close();
            
            System.out.println("==============================");
            
            ObjectInputStream ois = new ObjectInputStream(new FileInputStream(file));
            Object newP = ois.readObject();//没有强制转换到Person类
            ois.close();
            System.out.println(newP);
        }
}

运行后输出为:

arg constructor
==============================
Person [name=tony, age=23, gender=MALE,null]

1.此时必须注意的是,当重新读取被保存的Person对象时,并没有调用Person的任何构造器,看起来就像是直接使用字节将Person对象还原出来的。
当Person对象被保存到person.out文件中之后,我们可以在其它地方去读取该文件以还原对象,但必须确保该读取程序的CLASSPATH中包含有Person.class(哪怕在读取Person对象时并没有显示地使用Person类,如上例所示),否则会抛出ClassNotFoundException。

2.被transient修饰的变量,没有被序列化。

 3.为什么一个类实现了Serializable接口,它就可以被序列化呢?在上节的示例中,使用ObjectOutputStream来持久化对象,在该类中有如下代码:

 // remaining cases
            if (obj instanceof String) {
                writeString((String) obj, unshared);
            } else if (cl.isArray()) {
                writeArray(obj, desc, unshared);
            } else if (obj instanceof Enum) {
                writeEnum((Enum) obj, desc, unshared);
            } else if (obj instanceof Serializable) {
                writeOrdinaryObject(obj, desc, unshared);
            } else {
                if (extendedDebugInfo) {
                    throw new NotSerializableException(
                        cl.getName() + "\n" + debugInfoStack.toString());
                } else {
                    throw new NotSerializableException(cl.getName());
                }
            }

从上述代码可知,如果被写对象的类型是String,或数组,或Enum,或Serializable,那么就可以对该对象进行序列化,否则将抛出NotSerializableException。

3.serialVersionUID

   如果你的类序列化存到硬盘上面后,可是后来你却更改了类的field(增加或减少或改名),当你Deserialize时,就会出现Exception的,这样就会造成不兼容性的问题。
   但当serialVersionUID相同时,它就会将不一样的field以type的预设值Deserialize,可避开不兼容性问题。       

   在Eclipse里写代码时,开始如果没加这个serialVersionUID就有警告提示。Eclipse提供两种生成方式:
   一种是默认的1L,比如:private static final long serialVersionUID = 1L;
    一种是根据类名、接口名、成员方法及属性等来生成一个64位的哈希字段,比如:private static final long serialVersionUID = xxxxL;

 

参照博客https://blog.csdn.net/mashangyou/article/details/21833357这个深入的较多,有时间再看看。

转载于:https://www.cnblogs.com/recurision/p/10077380.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值