序列化 / 反序列化,常用于多台服务器之间进行java对象的数据传递


序列化


序列化是指把程序中准备好的 java对象 永久的保存在磁盘中,这个过程其实是一个out动作。

ObjectOutputStream:通过在流中使用文件可以实现对象的持久存储。
创建对象
ObjectOutputStream(OutputStream out)
常用方法
void writeObject(Objectobj) :将指定的对象写入 ObjectOutputStream。


反序列化


反序列化是指把磁盘中已经序列化好的文件读取到程序中,恢复成java对象的动作,是一个in的过程。

ObjectInputStream:对以前使用 ObjectOutputStream 写入的基本数据和对象进行反序列化。
创建对象
ObjectInputStream(InputStream in)
常用方法 Object readObject() :从ObjectInputStream 读取对象。


代码测试


  1. 创建学生类,测试序列化
package cn.*.Seriablizable;

import java.io.Serializable;

//想完成序列化 -- 必须实现接口表示开启序列化功能
public class Student implements Serializable {
    //给文件提供唯一的id
    private static final long serialVersionUID = 1L;
    private String name ;
    private int age ;
    //构造方法目的是为了方便外界创建对象
    public Student(){}

    public Student(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }
    //重写toString();目的是显示对象的属性值,而不是地址值

    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}
  1. 测试序列化和反序列化
package cn.*.Seriablizable;

import java.io.*;

public class Test01_Seriablizable {
    public static void main(String[] args) throws Exception {
        serialization();//序列化
        deserialization();//反序列化
    }

    /**
     * 序列化 -- 把程序中准备好的java对象永久地写出在磁盘里 - out
     */
    private static void serialization() throws Exception {
        //创建对象
        ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream(""));
        //完成序列化
        Student s = new Student("jack",18);
        out.writeObject(s);
        //释放资源
        out.close();
    }

    /**
     * 反序列化 -- 把已经序列化好的文件,恢复到java程序中
     */
    private static void deserialization() throws Exception {
        //创建对象
        ObjectInputStream in = new ObjectInputStream(new FileInputStream(""));
        //完成反序列化
        Object obj = in.readObject();
        System.out.println(obj);
        //释放资源
        in.close();
    }
}

编码转换流


转换流:专门用来把字节流转成字符流。是一个字节和字符流的转换桥梁。
InputStreamReader – 把字节读取流转成字符读取流,继承自Reader。

创建对象 :
InputStreamReader(InputStream in)
InputStreamReader(InputStream in, String charsetName)

OutputStreamWriter – 把字节写出流转成字符写出流,继承自Writer。

创建对象 :
OutputStreamWriter(OutputStream out)
OutputStreamWriter(OutputStream out, String charsetName)

代码测试:

package cn.*.Seriablizable;

import java.io.*;

public class Test02_Encoding {
    public static void main(String[] args) throws Exception {
        out();//测试 OutputStreamWriter
		in();//测试 InputStreamReader
    }

    private static void in() throws Exception {
        //1, 创建对象  -- 参数是字节流InputStream类型
        Reader in = new InputStreamReader(new FileInputStream(""));
        //2,读取数据
        int b = 0 ;
        while((b = in.read()) != -1){
            System.out.println(b);
        }
        //3,释放资源
        in.close();
    }

    private static void out() throws Exception {
        //创建对象  -- 参数是字节流OutputStream类型
        Writer out = new OutputStreamWriter(new FileOutputStream(""),"gbk");//解决乱码,修改编码
        //写出数据
        out.write(97);
        out.write(98);
        out.write("大家好,我叫渣渣辉");
        //释放资源
        out.close();
    }
}

编码与解码


概念

  • 编码就是把字符转换为字节,而解码是把字节重新组合成字符。
  • 如果编码和解码过程使用不同的编码方式那么就出现了乱码。

GBK 编码中,中文字符占 2 个字节,英文字符占 1 个字节;
UTF-8 编码中,中文字符占 3 个字节,英文字符占 1 个字节;
UTF-16be 编码中,中文字符和英文字符都占 2 个字节。

String 的编码方式

String 可以看成一个字符序列,可以指定一个编码方式将它编码为字节序列,也可以指定一个编码方式将一个字节序列解码为 String。

String str1 = "海王";
byte[] bytes = str1.getBytes("UTF-8");
String str2 = new String(bytes, "UTF-8");
System.out.println(str2);

在调用无参数 getBytes() 方法时,默认的编码方式不是 UTF-16be。双字节编码的好处是可以使用一个 char 存储中文和英文,而将 String 转为 bytes[] 字节数组就不再需要这个好处,因此也就不再需要双字节编码。getBytes() 的默认编码方式与平台有关,一般为 UTF-8。

byte[] bytes = str1.getBytes();

那么再想一个问题,不管是文件读写还是网络发送接收,信息的最小存储单元都是字节,那为什么 I/O 流操作要分为字节流操作和字符流操作呢?

既然有了字节流,为什么还要有字符流?

字符流是由 Java 虚拟机将字节转换得到的,问题就出在这个过程还算是非常耗时,并且,如果我们不知道编码类型就很容易出现乱码问题。所以, I/O 流就干脆提供了一个直接操作字符的接口,方便我们平时对字符进行流操作。如果音频文件、图片等媒体文件用字节流比较好,如果涉及到字符的话使用字符流比较好。