序列化和反序列化(投稿赚钱)

序列化:将对象的状态信息转换为可以存储或传输的形式的过程,在序列化期间,对象将其当前状态写入到临时或者持久性的存储区。

反序列化:通过从存储区读取或者反序列化对象,重新创建该对象。

1:对象如何序列化

 首先创建一个序列化的类

class Person implements Serializable {
    private String name;    private Integer age;    /**     * 1表示男 2表示女     */    private Integer sex;
    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 Integer getSex() {        return sex;    }
    public void setSex(Integer sex) {        this.sex = sex;    }
    @Override    public String toString() {        return "Person{" +                "name='" + name + '\'' +                ", age='" + age + '\'' +                ", sex=" + sex +                '}';    }}

然后创建一个序列化的方法,如下:

public static void serialize() throws IOException {        Person person = new Person();        person.setName("nick");        person.setAge(22);        person.setSex(1);        ObjectOutputStream objectOutputStream =                new ObjectOutputStream(new FileOutputStream(new File("person.txt")));        objectOutputStream.writeObject(person);        objectOutputStream.close();        System.out.println("序列化完成!");        System.out.println("==============================================");    }

执行后的结果如下:

序列化完成!==============================================

然后再反序列化,执行以下的反序列化方法​​​​​​​

public static void deserialize() throws IOException, ClassNotFoundException {        ObjectInputStream objectInputStream =                new ObjectInputStream(new FileInputStream(new File("person.txt")));        Person person = (Person) objectInputStream.readObject();        objectInputStream.close();
        System.out.println("反序列化结果如下:");        System.out.println(person);    }

反序列化得到的结果如下:​​​​​​​

反序列化结果如下:Person{name='nick', age='22', sex=1}

可以看到通过上面的方法能够进行正确的序列化和反序列化。

2:Serializable接口有何用?

上面在定义Person类时,实现了一个Serializable接口,然而当点进Serializable接口内部查看,发现它是一个空接口!

 * If a serializable class does not explicitly declare a serialVersionUID, then * the serialization runtime will calculate a default serialVersionUID value * for that class based on various aspects of the class, as described in the * Java(TM) Object Serialization Specification.  However, it is <em>strongly * recommended</em> that all serializable classes explicitly declare * serialVersionUID values, since the default serialVersionUID computation is * highly sensitive to class details that may vary depending on compiler * implementations, and can thus result in unexpected * <code>InvalidClassException</code>s during deserialization.  Therefore, to * guarantee a consistent serialVersionUID value across different java compiler * implementations, a serializable class must declare an explicit * serialVersionUID value.  It is also strongly advised that explicit * serialVersionUID declarations use the <code>private</code> modifier where * possible, since such declarations apply only to the immediately declaring * class--serialVersionUID fields are not useful as inherited members. Array * classes cannot declare an explicit serialVersionUID, so they always have * the default computed value, but the requirement for matching * serialVersionUID values is waived for array classes. * * @author  unascribed * @see java.io.ObjectOutputStream * @see java.io.ObjectInputStream * @see java.io.ObjectOutput * @see java.io.ObjectInput * @see java.io.Externalizable * @since   JDK1.1 */public interface Serializable {}

但是如果不实现Serializable接口,又会报错。

Exception in thread "main" java.io.NotSerializableException: com.serial.Person  at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1184)  at java.io.ObjectOutputStream.writeObject(ObjectOutputStream.java:348)  at com.serial.Serialize.serialize(Serialize.java:29)  at com.serial.Serialize.main(Serialize.java:18)

那为啥会报这个错呢?

通过跟踪代码可以看到如下代码

 // 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());                }            }

从上面的代码可以看到假如一个对象既不是字符串、数组、枚举,同时也没有实现Serializable接口的话,在序列化的时候就会抛出NotSerializableException异常!

3:serialVersionUID的作用

经常可以看到如下的定义

private static final long serialVersionUID = -4392638638228609589L;

它有以下两个作用

  • serialVersionUID是是否可以序列化的唯一标识符。serialVersionUID序列化ID,可以看成是序列化和反序列化过程中的“暗号”,在反序列化时,JVM会把字节流中的序列号ID和被序列化类中的序列号ID做比对,只有两者一致,才能重新反序列化,否则就会报异常来终止反序列化的过程。

  • 如果没有显式定义serialVersionUID,编译器会为它自动生成一个。 如果在定义一个可序列化的类时,没有人为显式地给它定义一个serialVersionUID的话,则Java运行时环境会根据该类的各方面信息自动地为它生成一个默认的serialVersionUID,一旦像上面一样更改了类的结构或者信息,则类的serialVersionUID也会跟着变化!

所以,为了serialVersionUID的确定性,凡是implements Serializable的类,最好人为显式地声明一个serialVersionUID值!

4:还有两种特殊情况

  • 凡是被static修饰的字段是不会被序列化的,因为序列化保存的是对象的状态而static是类的状态,所以会忽略static静态域是理所应当的。

  • 凡是被transient修饰符修饰的字段也是不会被序列化的,大家可以去了解一下transient修饰符的作用。如果在序列化某个类的对象时,就是不希望某个字段被序列化(比如密码),那这时就可以用transient修饰符来修饰该字段。

我们是一个技术分享平台,欢迎大家积极邮件投稿(请附带银行卡号和姓名)。为了激励大家的积极性,投稿发布后产生的广告收入,会全部通过转账的方式回馈给大家,大家也可以把文章分享到朋友圈,这样可以获得更多的广告收入。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值