序列化 / 反序列化,常用于多台服务器之间进行java对象的数据传递
序列化
序列化是指把程序中准备好的 java对象 永久的保存在磁盘中,这个过程其实是一个out动作。
ObjectOutputStream:通过在流中使用文件可以实现对象的持久存储。
创建对象
ObjectOutputStream(OutputStream out)
常用方法
void writeObject(Objectobj) :将指定的对象写入 ObjectOutputStream。
反序列化
反序列化是指把磁盘中已经序列化好的文件读取到程序中,恢复成java对象的动作,是一个in的过程。
ObjectInputStream:对以前使用 ObjectOutputStream 写入的基本数据和对象进行反序列化。
创建对象
ObjectInputStream(InputStream in)
常用方法 Object readObject() :从ObjectInputStream 读取对象。
代码测试
- 创建学生类,测试序列化
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 +
'}';
}
}
- 测试序列化和反序列化
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 流就干脆提供了一个直接操作字符的接口,方便我们平时对字符进行流操作。如果音频文件、图片等媒体文件用字节流比较好,如果涉及到字符的话使用字符流比较好。