Java之序列化------自用


本文参考文章:http://mp.weixin.qq.com/s?__biz=MzIwOTE2MzU4NA==&mid=2247484021&idx=1&sn=d7760254bd36f3a39dc8705ad40b469f&chksm=9779465aa00ecf4cfb5513a0ac41a31f318df2565b3e4ac739e62abfedad21d5a1e483f63f63&scene=0&xtrack=1#rd

1.什么叫序列化

序列化:把Java对象转换成字节序列的过程
反序列化:把字节序列转换成对象的过程
在这里插入图片描述

2.为什么要序列化及序列化的用途

因为虚拟机一旦运行结束,Java对象的生命也就结束了,如果我们还是想继续在以后用该对象,或者想把该对象传输给另一台机器,就只能将其转换成字节序列存储在文件和数据库中,或者通过网络传输给另一台机器。

序列化的用途:

  • 减轻内存压力的同时,持久化

比如 Web服务器中的Session对象,当有 10+万用户并发访问的,就有可能出现10万个Session对象,内存可能消化不良,于是Web容器就会把一些seesion先序列化到硬盘中,等要用了,再把保存在硬盘中的对象还原到内存中。

  • 让Java对象可以在网络中进行传输。

我们在使用Dubbo远程调用服务框架时,需要把传输的Java对象实现Serializable接口,即让Java对象序列化,因为这样才能让对象在网络上传输。

3. 常用的API

3.1 Serializable接口

Serializable接口是一个标记接口,没有方法或字段。一旦实现了此接口,就标志该类的对象就是可序列化的。

public interface Serializable {
    
    
}

3.2 Externalizable 接口

Externalizable继承了Serializable接口,还定义了两个抽象方法:writeExternal()和readExternal(),如果开发人员使用Externalizable来实现序列化和反序列化,需要重写writeExternal()和readExternal()方法

public interface Externalizable extends java.io.Serializable{
    
    
void writeExternal(ObjectOutput out)throws IOException;
void readExternal(ObjectInput in)throws IOException,ClassNotFoundException;
}

3.3 java.io.ObjectOutputStream类

表示对象输出流,它的writeObject(Object obj)方法可以对指定obj对象参数进行序列化,再把得到的字节序列写到一个目标输出流中。

3.4 java.io.ObjectInputStream类

表示对象输入流, 它的readObject()方法,从输入流中读取到字节序列,反序列化成为一个对象,最后将其返回。

4.序列化的使用

首先创建一个对象User

package com.company;

import java.io.Serializable;

public class User implements Serializable {
    
    
    private String name;
    private Integer age;
    private String 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 String getSex() {
    
    
        return sex;
    }

    public void setSex(String sex) {
    
    
        this.sex = sex;
    }

    @Override
    public String toString() {
    
    
        return "User{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", sex='" + sex + '\'' +
                '}';
    }
}

然后使用ObjectOutputStream ObjectInputStream测试

 ObjectOutputStream objectOutputStream=new ObjectOutputStream(new FileOutputStream("D:\\text.out"));
        User user=new User();
        user.setAge(22);
        user.setName("Daniel");
        user.setSex("男");
        objectOutputStream.writeObject(user);
        objectOutputStream.flush();
        objectOutputStream.close();

        ObjectInputStream objectInputStream=new ObjectInputStream(new FileInputStream("D:\\text.out"));
        User user1=(User) objectInputStream.readObject();
        user1.setName("jjp");
        System.out.println(user1);

输出结果:

User{name=‘jjp’, age=22, sex=‘男’}

5.序列化底层

writeObject的部分源码:

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

ObjectOutputStream 在序列化的时候,会判断被序列化的Object是哪一种类型,String?array?enum?还是 Serializable,如果都不是的话,抛出 NotSerializableException异常。所以呀,Serializable只是一个标志,一个序列化标志~

6.序列化的注意点

6.1 static静态变量和transient 修饰的字段是不会被序列化的

在这里插入图片描述
我们将age设为静态变量,,sex设为transient变量

package com.company;

import java.io.*;

public class Main {
    
    

    public static void main(String[] args) throws IOException, ClassNotFoundException {
    
    
        ObjectOutputStream objectOutputStream=new ObjectOutputStream(new FileOutputStream("D:\\text.out"));
        User user=new User();
        user.setAge(22);
        user.setName("Daniel");
        user.setSex("男");
        System.out.println(user);
        objectOutputStream.writeObject(user);
        objectOutputStream.flush();
        objectOutputStream.close();

        user.setAge(56);
        ObjectInputStream objectInputStream=new ObjectInputStream(new FileInputStream("D:\\text.out"));
        User user1=(User) objectInputStream.readObject();
        System.out.println(user1);
    }
}

程序运行结果如下:

User{name=‘Daniel’, age=22, sex=‘男’}
User{name=‘Daniel’, age=56, sex=‘null’}

  • 可以看出静态变量是不会写入序列化的文件中的,这是因为static变量是类级别的,而序列化针对的是对象。
  • 被transient修饰的变量序列化时,其值变为初始值,如果时基本类型如int是0,如果是对象则是null**

6.2 SerialVerisonUID

JAVA序列化的机制是通过判断类的serialVersionUID来验证版本是否一致的。在进行反序列化时,JVM会把传来的字节流中的serialVersionUID和本地相应实体类的serialVersionUID进行比较,如果相同,反序列化成功,如果不相同,就抛出InvalidClassException异常。

6.3 如果某个序列化类的成员变量是对象类型,则该对象类型的类必须实现序列化

6.4 子类实现了Serializable,父类没有实现Serializable接口的话,父类不会被序列化。

猜你喜欢

转载自blog.csdn.net/weixin_42684418/article/details/105689094
今日推荐