概述
-
序列化是指将对象的状态信息转换为可以存储或传输形式的过程.在序列化期间,对象将其当前状态写入到临时或持久性存储区.以后可以通过从存储区中读取或者反序列化对象的状态,重新创建该对象.
-
序列化:利用ObjectOutputStream,把对象的信息,按照固定的格式转成一串字节值输出并持久保存到磁盘
反序列化:利用ObjectInputStream,读取磁盘中之前序列化好的数据,重新恢复成对象
特点
需要序列化的文件必须实现Serializable接口,用来启用序列化功能
不需要序列化的数据可以修饰成static,原因:static资源属于类资源,不随着对象被序列化输出
每一个被序列化的文件都有一个唯一的id,如果没有添加此id,编译器会自动根据类的定义信息计算产生一个
在反序列化时,如果和序列化的版本号不一致,无法完成反序列化
常用与服务器之间的数据传输,序列化成文件,反序列化读取数据
常用使用套接字流在主机之间传递对象
不需要序列化的数据也可以被修饰成transient(临时的),只在程序运行期间在内存中存在,不会被序列化持久保存
package cn.tedu.encoding;
/**
* 本类用于测试编码转换流
* @author ZHU
* @create 17/08/2021 15:33
*/
public class TestEncode {
public static void main(String[] args) {
f1();
f2();
}
/**用于测试OutputStreamReader*/
private static void f2() {
}
/**用于测试InputStreamReader*/
private static void f1() {
}
}
package cn.tedu.file;
import java.io.*;
import java.util.Scanner;
/**
* @author ZHU
* @create 17/08/2021 10:21
*/
public class TestCopyFile {
public static void main(String[] args) {
System.out.println("请输入源文件路径:");
String f = new Scanner(System.in).nextLine();//--复制啥
System.out.println("请输入目标文件路径:");
String t = new Scanner(System.in).nextLine();//--复制到哪
ZFCopy(f,t);
// ZJCopy(f,t);
}
private static void ZFCopy(String f, String t) {
//1.定义再整个方法中都生效的局部变量,手动初始化值为null
InputStream in = null;
OutputStream out = null;
//2.由于代码可能会发生异常,所以需要try-catch -finally 结构
try{
//3.创建高效/缓冲字节输入流,参数是f
in =new BufferedInputStream(new FileInputStream(f));
//3.2 创建高效/缓冲字节输出流 , 参数是t
out = new BufferedOutputStream(new FileOutputStream(t));
//4 创建好流对象以后就可以通过流对象完成业务了
//4.1 定义变量保存读到的数据
int b;
while((b = in.read()) != -1){
out.write(b);
}
System.out.println("恭喜您,文件复制成功");
}catch (Exception e){
System.out.println("很抱歉,文件复制失败");
e.printStackTrace();
}finally {
//5.关流
try {
out.close();
} catch (IOException e) {
e.printStackTrace();
}
try {
in.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
private static void ZJCopy(String f, String t) {
Writer out = null;
Reader in = null;
try{
//3.创建高效/缓冲字符输出流,输入的参数是源文件的路径
in = new BufferedReader(new FileReader(f));
//3.2 创建高效/缓冲字符输出流,传入的参数是目标文件的路径
out = new BufferedWriter(new FileWriter(t));
//4.拿到流对象以后,就可以使用流对象来完成业务了
//4.1 定义变量用来记录读到的数据
int b;
//4.2 循环读取目标文件,知道返回值为-1,没有数据时结束循环
while(( b = in.read()) != -1){
out.write(b);//将本次循环从源文件读到的内容写出到目标文件中
}
}catch (Exception e){
e.printStackTrace();
}finally {
/**
* 关流是有顺序的: 如果有多个流,最后创建的流最先关闭
* 多条关流语句需要各自try - catch
*/
try {
out.close();
// in.close();
} catch (IOException e) {
e.printStackTrace();
}
try {
in.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
package cn.tedu.generic;
import java.util.ArrayList;
import java.util.List;
/**
* 本类用于测试泛型的好处1
* @author ZHU
* @create 17/08/2021 16:41
*/
public class TestGeneric {
public static void main(String[] args) {
//1.定义一个String类型,长度为5的数组
String[] a = new String[5];
a[2] = "paopao";
a[4] = "xiaxia";
//数组的好处: 在编译时期检查数据的类型,如果不是要求的类型会在编译期就报错
/**
* 1.泛型是怎么来的?? -- 想要模拟数组的数据类型检查
* 2.泛型通常结合着集合一起使用
*/
//没有泛型,数据类型根本没有约束
List list = new ArrayList<>();
list.add("taotao");
list.add(1);
list.add(7.7);
list.add('a');
System.out.println(list);
/**
* 引入泛型
* 主要目的是检查约束集合中元素的类型
*/
/**
* 泛型的好处: 可以把报错的时机提前,在编译期就博报错,而不是运行后才抛出错误
* 在向集合中添加元素时,会先检查元素的数据类型,如果不是要求的数据类型就编译失败
*/
List<String> list2 = new ArrayList<>();
list2.add("leishen"); // 约束了集合类型以后,只可以传String类型的参数
//list2.add(1)
/**
* <type> --type 的值必须是引用类型,不能使用基本类型
* 至于使用什么引用类型,取决于自己的业务
*/
List<Integer> list3 = new ArrayList<>();
}
}
package cn.tedu.generic;
/**
* 本类用于测试泛型的优点2
* @author ZHU
* @create 17/08/2021 17:17
*/
public class TestGeneric2 {
public static void main(String[] args) {
Integer[] a = {1,2,3,4,5,6,7,8,9,10};
print(a);
String[] b = {"f","saf","sdf","sf","jsdflkp","slkfjf","lsjdgi","klasdf"};
print(b);
Double[] c = {6.0, 6.6,6.66,6.666};
print(c);
}
/**
* 1.泛型可以实现通用代码的编写,使用E表示元素的类型element类型
* 泛型的语法要求: 如果在使用方法上使用泛型, 必须两处同时出现
* 一个是方法传入参数的类型是泛型,一个是返回值前加泛型<E>
* @param cE
*/
private static <E>void print(E[] c) {
for ( E d :
c) {
System.out.println(d);
}
}
/* private static void print(String[] b) {
for (String s :
b) {
System.out.println(s);
}
}
private static void print(Integer[] a) {*/
/* for (int i = 0; i < a.length; i++) {
System.out.println(a[i]);
}*/
//2.使用高效/增强for循环来遍历数组中的元素
/**
* 高效for循环:
* 格式: for(2 3 : 1) {循环体} 1 要遍历的数据 2 每轮要遍历到的数据类型 3. 变量的名字
* 好处: 比普通for循环写法简单,效率高
* 坏处: 没有办法想普通for循环那样根据下标来操作值,只能从头到尾依次遍历
*/
/* for (Integer i:
a) {
System.out.println(i);
}
}*/
}
package cn.tedu.review;
import java.io.*;
/**
* 本类用于复习IO流对象的创建
* @author ZHU
* @create 17/08/2021 09:05
*/
public class TestIOCreate {
public static void main(String[] args) {
/*字节输入流*/
//InputStream
try {
FileInputStream in = new FileInputStream(new File(""));
FileInputStream in2 = new FileInputStream("");
BufferedInputStream in3 = new BufferedInputStream(new FileInputStream(new File("")));
BufferedInputStream in4 = new BufferedInputStream(new FileInputStream(""));
} catch (FileNotFoundException e) {
e.printStackTrace();
}
/*字节输出流*/
//OutputStream
try {
FileOutputStream out = new FileOutputStream("");
FileOutputStream out2 = new FileOutputStream("",true);
FileOutputStream out3 = new FileOutputStream(new File(""));
FileOutputStream out4 = new FileOutputStream(new File(""),true);
//这个位置传上述4个中任意一个FOS对象都可以
BufferedOutputStream out5 = new BufferedOutputStream(new FileOutputStream(""));
} catch (FileNotFoundException e) {
e.printStackTrace();
}
/*字符输入流*/
//Reader
try {
FileReader in5 = new FileReader("");
FileReader in6 = new FileReader(new File(""));
BufferedReader in7 = new BufferedReader(new FileReader(""));
BufferedReader in8 = new BufferedReader((new FileReader(new File(""))));
} catch (FileNotFoundException e) {
e.printStackTrace();
}
/*字符输出流*/
//Writer
try {
FileWriter out6 = new FileWriter(String.valueOf(new FileOutputStream(new File(""))));
FileWriter out7 = new FileWriter("");
FileWriter out8 = new FileWriter(new File(""));
FileWriter out9 = new FileWriter(new File(""),true);
BufferedWriter out10 = new BufferedWriter(new FileWriter(""));
BufferedWriter out11 = new BufferedWriter(new FileWriter("",true));
BufferedWriter out12 = new BufferedWriter(new FileWriter(new File("")));
BufferedWriter out13 = new BufferedWriter(new FileWriter(new File(""),true));
} catch (IOException e) {
e.printStackTrace();
}
}
}
package cn.tedu.serializable;
import java.io.Serializable;
/**
*
* @author ZHU
* @create 17/08/2021 11:43
*/
public class Student implements Serializable {
/**
* 每次反序列化时,会拿着之前序列化生成的UID作比较
* 只有两个UID一致时才能反序列化成功,否则报错
* 解决方案1: 一次序列化操作对应一次反序列化操作
* 解决方案2: 将UID写死,无论怎么修改Student类,UID都不变
*
*/
//1.创建学生类的属性
//private static final long serializableUID =1
private String name;
private int age;
private String addr;
private char gender;
//private char gender1;
//private char gender2;
public Student() {
System.out.println("我是Student的无参构造");
}
//4.添加重写的方法toString(),想查看对象的属性值而不是地址值
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
", addr='" + addr + '\'' +
", gender=" + gender +
'}';
}
public Student(String name, int age, String addr, char gender) {
this.name = name;
this.age = age;
this.addr = addr;
this.gender = gender;
}
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;
}
public String getAddr() {
return addr;
}
public void setAddr(String addr) {
this.addr = addr;
}
public char getGender() {
return gender;
}
public void setGender(char gender) {
this.gender = gender;
}
}
package cn.tedu.serializable;
import java.io.*;
/**
* 本类用于测试序列化与反序列化
* 序列化: 是指把程序中的java对象永久保存在磁盘中,比如文件
* 相当于是写出的过程,方向是out,用到的流是ObjectOutputStream
* 反序列化: 是指把已经序列化在文件中保存的数据,读取/恢复成java对象的过程
* 相当于是读取的过程,方向是in,用到的流是ObjectInputStream反序列化流
*
* 如果一个类的对象想要被序列化输出,那么这个类必须安装序列化接口,否则会报错
* java.io.NotSerializableException: cn.tedu.serializable.Student
* at java.io.ObjectOutputStream.writeObject0
*
* Serializable 接口是一个空接口,里面一个方法都没有
* 作用是当做标志,标志这个类可以被序列化
* @author ZHU
* @create 17/08/2021 11:53
*/
public class TestSerializable {
public static void main(String[] args) {
method1();
methed2();
}
/**
* 反序列化方法
*/
private static void methed2() {
//1.声明一个在本方法内都生效的局部标量,手动初始化值为null
ObjectInputStream in = null;
//2.由于IO流操作可能会产生异常,所以需要使用try-catch-finally结构
try{
in = new ObjectInputStream(new FileInputStream(new File("D:\\TestFile\\1.txt")));
//4.通过OIS反序列化流对象来读取恢复对象
Object o = in.readObject();
System.out.println(o);
System.out.println("恭喜您! 反序列化成功");
}catch (Exception e){
System.out.println("很抱歉!, 反序列化失败");
e.printStackTrace();
}finally {
try {
in.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
/**
* 序列化
*/
private static void method1() {
//1.声明一个在本方法中都生效的局部变量,手动初始化值为null
ObjectOutputStream out = null;
//2.由于IO操作可能会发生异常,所以使用try - catch - finally
try{
out = new ObjectOutputStream(new FileOutputStream("D:\\TestFile\\1.txt"));
//4.指定一个要序列化输出的对象
Student obj = new Student("likui",16,"liushuxia",'男');
//5.使用oos流将对象输出
out.writeObject(obj);
System.out.println("恭喜您,序列化成功");
}catch(Exception e){
System.out.println("很抱歉,序列化失败");
e.printStackTrace();
}finally{
//6.关流
try {
out.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}