欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Java深度学习系列——对象流和序列化

程序员文章站 2022-07-09 23:09:20
...

前言:

我是张哲,一位在互联网上不愿透露姓名的小学员,接下来大家看到的所有内容都是我背写的知识点,这里的知识点和你所学习到的不同,我中和了我的一些书籍和网上刷的面试笔记,相信这里能让你接触到更深入的知识点,我会慢慢的把我对某个知识点的理解写进去。

常见的几种数据存储:变量、数组、对象、集合、文件、数据库
我们想文件中存储的是数据,可是文件中能不能存储对象呢??对象的属性,属性值,方法这些??
于是就是有了对象流,ObjectInputStream、ObjectOutputStream,对象流是一种高级流,所以在实例化对象的时候需要一个低级流当做参数

怎么把一个对象存储在文件中呢?
static class Person{
		private String name;
		private int age;
		public Person(){
			
		}
		public Person(String name, int age) {
			super();
			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;
		}
		
	}
	public static void main(String[] args) {
		try {
			FileOutputStream writer=new FileOutputStream("C:\\Users\\张哲\\Desktop/申请.txt");
			ObjectOutputStream out=new ObjectOutputStream(writer);
			Person p=new Person("张哲",18);
			out.writeObject(p);
			out.flush();
			
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
  //运行的结果是个运行时异常:java.io.NotSerializableException
  //它的意思是Person类没有实现序列化接口所以我们

那什么是序列化和反序列化呢?

序列化:将一个对象拆解成很多的字节碎片的过程。
反序列化:将一些字节碎片重组成一个对象的过程。
所以我们刚刚出现了异常:java.io.NotSerializableException,是因为我们用对象流将一个对象序列化到文件中,但是我们不去实现序列化接口怎么去序列化呢?这个就是原因了。

下面来看看序列化接口的源码:

public interface Serializable {
}
//噗噗,是不是很搞笑,啥属性,啥方法也没有。
//像这样的接口我们叫它:示意性接口
//就是个标识的意思,你要想实现某些功能还必须实现某个接口,尽管它里面没有什么抽象方法
现在我们让Person类去实现Serializable接口,在运行下
static class Person implements Serializable{
		private String name;
		private int age;
		public Person(){
			
		}
		public Person(String name, int age) {
			super();
			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;
		}		
	}
	public static void main(String[] args) {
		try {
			FileOutputStream writer=new FileOutputStream("C:\\Users\\张哲\\Desktop/申请.txt");
			ObjectOutputStream out=new ObjectOutputStream(writer);
			Person p=new Person("张哲",18);
			out.writeObject(p);
			out.flush();
			
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
 //最终正常运行结束

打开对应的文件后内容为:

 {sr java.io.NotSerializableException(Vx 鐔5 xr
java.io.ObjectStreamExceptiond娩k? xr java.io.IOExceptionl€sde%皤 xr
java.lang.Exception旋>;? xr java.lang.Throwable掌5’9w杆 L causet
Ljava/lang/Throwable;L detailMessaget Ljava/lang/String;[
stackTracet [Ljava/lang/StackTraceElement;L suppressedExceptionst
Ljava/util/List;xpq ~ t org.tt.zz.main.LambdaDemoKaTeX parse error: Expected 'EOF', got '&' at position 86: …TraceElementa 艢&̲6輩 I lineNumbe…UnmodifiableList?%1奠? L listq ~ xr
,java.util.Collections$UnmodifiableCollectionB €薧? L ct
Ljava/util/Collection;xpsr java.util.ArrayListx佉櫱a? I sizexp w
xq ~ x

哈哈,我知道你看不懂,我也看不懂。。。[坏笑]
不过没关系,这就是个序列化的过程,把对象的信息打碎了存入我们的文件中来,这样也起到了一定的加密安全。

我们要怎样读取文件中的数据返还成正常的数据呢?//下面来看看我 try 中的代码块
 FileOutputStream writer=new FileOutputStream("C:\\Users\\张哲\\Desktop/申请.txt");
	ObjectOutputStream out=new ObjectOutputStream(writer);
	Person p=new Person("张哲",18);
	out.writeObject(p);
	out.flush();
		
	FileInputStream reader=new FileInputStream("C:\\Users\\张哲\\Desktop/申请.txt");
	ObjectInputStream in=new ObjectInputStream(reader);
	Person p1=(Person)in.readObject();
	System.out.println(p1.getName()+p1.getAge());

看这样就是个序列化和反序列化的过程,除此之外我们先能不能一次性存储多个对象呢?

//下面来看看我 try 中的代码块
    FileOutputStream writer=new FileOutputStream("C:\\Users\\张哲\\Desktop/申请.txt");
	ObjectOutputStream out=new ObjectOutputStream(writer);
	Person p1=new Person("张三",18);
	Person p2=new Person("李四",50);
	Person p3=new Person("王五",26);
	out.writeObject(p1);
	out.writeObject(p2);
	out.writeObject(p3);
	out.flush();
 //他也是可以正常运行的,取出的时候用推荐用数组,这里不再过多说明
如果前后类模板不一致怎样解决?

这个问题我把它分成两种情况
一:文件中的类模板属性少于Java程序中的属性
二:文件中的类模板属性多于Java程序中的属性
这个问题不是没有,我们可能会根据各种需求,增加属性和删掉属性。比如:

//序列化时程序的属性
private String name;
private int age;

//反序列化时程序的属性
private String name;
private int age;
private int count;

//前后发生了运行时异常
java.io.InvalidClassException
如以上代码,出现这个问题如何解决呢?

原因是缺少一个序列化版本号,有了它才能更好的做序列化和反序列化之间的”兼容“操作,保证对象的构建和拆解是统一的。

//序列化版本号:
private final static long serialVersionUID = 2472549717346527430L;
//序列化版本号的值可以手动设置,是一个long类型
//再来试试加了序列化版本号之后的效果:
//序列化时的程序的属性
private String name;
private int age;
private final static long serialVersionUID = 2472549717346527430L;

//反序列化时程序的属性
private String name;
private int age;
private int count;
private final static long serialVersionUID = 2472549717346527430L;
//最终的结果是程序正常运行
//反序列化时多的那个属性会初始化默认值

这里特别说明:序列化版本号一致的情况下:如果序列化的属性比反序列化的少,则反序列化时多出来的属性初始化默认值,如果序列化属性比反序列化时多,程序会自动去掉多的部分。

属性相关的影响:

transientstatic修饰的属性在序列化时不会被写入文件。

  • transient是序列化方面的特征修饰符。
  • static修饰的属性属于类,不会被对象流写入文件。
相关标签: java java