Java中对象的序列化和反序列化操作

Java的IO流不仅可以对字符进行传输,也可以对对象进行传输,叫做对象的序列化和反序列化
在这里插入图片描述
序列化:将对象转为方便传输的流(对象写入文件)
反序列化:将流转换成对应的对象(把对象从文件中拿出)

注意:如果我们需要将对象序列化到文件,首先需要让需要序列化对象对应的类实现序列化接口Serializable,该接口中没有任何方法和属性,仅仅只是一个标志,表示实现该接口的类是可以被序列化的;如果没有实现该接口就进行序列化,会报出NotSerializableException没有序列化的异常

import java.io.Serializable;

public class User implements Serializable {
	/**
	 * 用户名
	 */
	String userName;
	/**
	 * 密码
	 */
	String password;
	
	public User() {
		
	}
	
	public User(String deliverUserName,String deliverPassword) {
		userName = deliverUserName;
		password = deliverPassword;
	}

	@Override
	public String toString() {
		return "User [userName=" + userName + ", password=" + password + "]";
	}
	
}

1.对象进行序列化和反序列化

序列化和反序列化

类名方法名作用
序列化ObjectOutputStreamvoid write(Object obj)将指定的对象序列化到流中
反序列化ObjectInputStreamObject readObject()将流反序列化为对象并返回

序列化
序列化使用的是对象的输出流ObjectOutputStream(OutputStream out),使用时,传递的是一个字节输出流

	//创建对象序列化的对象
	ObjectOutputStream oos = null;
		try {
			oos = new ObjectOutputStream(new FileOutputStream("src/com/test/ser/user.txt",true));
		}catch (IOException e) {
			e.printStackTrace();
		}finally {
			//释放资源
			if(oos!=null) {
				try {
					oos.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}

成功创建对象的输出流后,我们就需要创建对象,然后吧对象进行序列化了

		//创建对象序列化的对象
		ObjectOutputStream oos = null;
		try {
			oos = new ObjectOutputStream(new FileOutputStream("src/com/test/ser/user.txt",true));
			//创建User的对象
			User user = new User("java","123456");
			//讲user序列化到文件中
			oos.writeObject(user);
			System.out.println("序列化成功");
		}catch (IOException e) {
			e.printStackTrace();
		}finally {
			//释放资源
			if(oos!=null) {
				try {
					oos.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}

序列化成功后,就可以在文件中看到我们序列化后的对象了
在这里插入图片描述
注意:序列化的时候会写进一个头标,这头标就是定位的,当我们反序列化的时候,会从这个头标开始读取;每次序列化对象都会写入一个头标,当我们反序列化读取多个对象的时候就会报出StreamCorruptedException: invalid type code: AC的异常
为什么会这样呢?
因为序列化的时候都会调用writeStreamHeader()方法,该方法就是用于写头标的,每次序列化都会调用该方法
为了避免写入多个头标,所以我们可以实现他的一个子类,然后空实现这个方法来防止多个头标的出现

import java.io.IOException;
import java.io.ObjectOutputStream;
import java.io.OutputStream;

public class Sub extends ObjectOutputStream {

	public Sub(OutputStream out) throws IOException {
		super(out);
	}
	
	@Override
	protected void writeStreamHeader() throws IOException {
		
	}
}

空实现这个方法后,我们使用的时候,如果文件是空的时候就创建父类的对象,如果文件不为空的时候就可以创建子类的对象来防止出现多个头标

		//创建对象序列化的对象
		ObjectOutputStream oos = null;
		try {
			//创建文件类封装文件路径
			File file = new File("src/com/test/ser/user.txt");
			//判断是否为空
			if(file.length()<1) {
				oos = new ObjectOutputStream(new FileOutputStream(file,true));
			}else {
				oos = new Sub(new FileOutputStream(file,true));
			}
			//创建User的对象
			User user = new User("java","123456");
			//讲user序列化到文件中
			oos.writeObject(user);
			System.out.println("序列化成功");
		}catch (IOException e) {
			e.printStackTrace();
		}finally {
			//释放资源
			if(oos!=null) {
				try {
					oos.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}

通过一个File类中length()方法进行判断就可以根据需要进行不同对象的创建,防止了多个头标出现而导致的异常

反序列化
反序列化使用的是ObjectInputStream(InputStream in),使用时需要我们传递的是一个字节输入流

		//创建反序列化的对象
		ObjectInputStream ois = null;
		try {
			ois = new ObjectInputStream(new FileInputStream("src/com/test/ser/user.txt"));
		} catch (IOException e) {
			e.printStackTrace();
		}finally {
			//释放流
			if(ois!=null) {
				try {
					ois.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}

创建对象后就可以去指定文件拿取对象了

// 创建反序列化的对象
		ObjectInputStream ois = null;
		try {
			ois = new ObjectInputStream(new FileInputStream("src/com/test/ser/user.txt"));
			// 用于接收的对象
			Object obj = null;
			// 开始读取
			while ((obj = ois.readObject()) != null) {
				User user = (User) obj;
				System.out.println(user.toString());
			}
			/*
			 * 打印结果:
			 * User [userName=java, password=123456] 
			 * java.io.EOFException 
			 * atjava.io.ObjectInputStream$BlockDataInputStream.peekByte(ObjectInputStream.java:2917) 
			 * atjava.io.ObjectInputStream.readObject0(ObjectInputStream.java:1502) 
			 * atjava.io.ObjectInputStream.readObject(ObjectInputStream.java:422) 
			 * atcom.test.ser.UserDeserializableTest.main(UserDeserializableTest.java:16)
			 */
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			// 释放流
			if (ois != null) {
				try {
					ois.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}

通过打印结果可以看到报出了EOFException异常,这个异常表示的是,读取用的指针已经到达末尾了,所以可以多一个catch来异常解决即可

// 创建反序列化的对象
		ObjectInputStream ois = null;
		try {
			ois = new ObjectInputStream(new FileInputStream("src/com/test/ser/user.txt"));
			// 用于接收的对象
			Object obj = null;
			// 开始读取
			while ((obj = ois.readObject()) != null) {
				User user = (User) obj;
				System.out.println(user.toString());
			}
			/*
			 * 打印结果:
			 * User [userName=java, password=123456]
			 * 读取完毕
			 */
		} catch(EOFException e) {
			System.out.println("读取完毕");
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			// 释放流
			if (ois != null) {
				try {
					ois.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}

这样我们就可以通过反序列化拿到文件中的对象了

今天的分享就到这里了,欢迎大家来一起交流学习!

  • 3
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值