Java序列化细节及实例

本文深入探讨Java序列化的几个关键方面,包括静态变量的序列化行为、如何实现简单的字段加密以及序列化过程中的存储规则。通过具体示例展示了序列化过程中的一些重要特性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Java序列化细节及实例

静态变量的序列化

代码:

public class Test01 implements Serializable {
		static int a = 10; 
		
	public static void main(String[] args) throws FileNotFoundException, IOException, ClassNotFoundException {
		ObjectOutputStream objectOutputStream = new ObjectOutputStream(new FileOutputStream("re.obj"));
		objectOutputStream.writeObject(new Test01());
		objectOutputStream.close();
		
		Test01.a = 50;
		ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream("re.obj"));
		Test01 test01 = (Test01) objectInputStream.readObject();
		System.out.println(test01.a);
		objectInputStream.close();
	}

}

结果输出50原因在于序列化时,并不保存静态变量,序列化保存的是对象的状态,静态变量属于类的状态,因此 序列化并不保存静态变量。

简单字段加密

代码:

public class pass implements Serializable{

	private static final long serialVersionUID = 1L;
	private String password = "pass";
	public String getPassword() {
	    return password;
	}
	public void setPassword(String password) {
	    this.password = password;
	}
	 
	private void writeObject(ObjectOutputStream out) {
	    try {
	        PutField putFields = out.putFields();
	        System.out.println("原密码:" + password);
	        password = "encryption";//模拟加密
	        putFields.put("password", password);
	        System.out.println("加密后的密码" + password);
	        out.writeFields();
	    } catch (IOException e) {
	        e.printStackTrace();
	    }
	}
	 
	private void readObject(ObjectInputStream in) {
	    try {
	        GetField readFields = in.readFields();
	        Object object = readFields.get("password", "");
	        System.out.println("要解密的字符串:" + object.toString());
	        password = "pass";//模拟解密,需要获得本地的密钥
	    } catch (IOException e) {
	        e.printStackTrace();
	    } catch (ClassNotFoundException e) {
	        e.printStackTrace();
	    }
	 
	}
	 
	public static void main(String[] args) {
	    try {
	        ObjectOutputStream out = new ObjectOutputStream(
	                new FileOutputStream("result.obj"));
	        out.writeObject(new pass());
	        out.close();
	 
	        ObjectInputStream oin = new ObjectInputStream(new FileInputStream(
	                "result.obj"));
	        pass t = (pass) oin.readObject();
	        System.out.println("解密后的字符串:" + t.getPassword());
	        oin.close();
	    } catch (FileNotFoundException e) {
	        e.printStackTrace();
	    } catch (IOException e) {
	        e.printStackTrace();
	    } catch (ClassNotFoundException e) {
	        e.printStackTrace();
	    }
	}   
	
	
}

输出:

原密码:pass
加密后的密码encryption
要解密的字符串:encryption
解密后的字符串:pass
序列化存储规则

代码:

public class Test02 implements Serializable{

	public static void main(String[] args) throws FileNotFoundException, IOException, ClassNotFoundException 	{

		ObjectOutputStream objectOutputStream = new ObjectOutputStream(new FileOutputStream("a.obj"));
		Test02 test02 = new Test02();
		objectOutputStream.writeObject(test02);
		objectOutputStream.flush();
		System.out.println(new File("a.obj").length());
		objectOutputStream.writeObject(test02);
		objectOutputStream.close();
		System.out.println(new File("a.obj").length());
		
		ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream("a.obj"));
		Test02 t1 = (Test02) objectInputStream.readObject();
		Test02 t2 = (Test02) objectInputStream.readObject();
		System.out.println(t1==t2);
	}

}

输出:

40
45
true

对同一对象两次写入文件,打印出写入一次对象后的存储大小和写入两次后的存储大小,然后从文件中反序列化出两个对象,比较这两个对象是否为同一对象。 可以看到:第二次写入对象时文件只增加了 5 字节,并且两个对象是相等的, Java 序列化机制为了节省磁盘空间,具有特定的存储规则,当写入文件的为同一对象时,并不会再将对象的内容进行存储,而只是再次存储一份引用,上面增加的 5 字节的存储空间就是新增引用和一些控制信息的空间。反序列化时,恢复引用关系,使得清单 3 中的 t1 和 t2 指向唯一的对象,二者相等,输出 true。该存储规则极大的节省了存储空间。

再有:

public class Test03 implements Serializable{
	 int a = 10;
	public static void main(String[] args) throws IOException, ClassNotFoundException {
		ObjectOutputStream objectOutputStream = new ObjectOutputStream(new FileOutputStream("a.obj"));
		Test03 test03 = new Test03();
		objectOutputStream.writeObject(test03);
		objectOutputStream.flush();
		test03.a = 50;
		objectOutputStream .writeObject(test03);
		objectOutputStream.close();
		
		ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream("a.obj"));
		Test03 t1 = (Test03) objectInputStream.readObject();
		Test03 t2 = (Test03) objectInputStream.readObject();
		System.out.println(t1.a);
		System.out.println(t2.a);
	}

}

将 test03对象两次保存到 a.obj 文件中,写入一次以后修改对象属性值再次保存第二次,然后从 a.obj 中再依次读出两个对象,输出这两个对象的 a性值。结果两个输出的都是10, 原因就是第一次写入对象以后,第二次再试图写的时候,虚拟机根据引用关系知道已经有一个相同对象已经写入文件,因此只保存第二次写的引用,所以读取时,都是第一次保存的对象。所以在使用一个文件多次 writeObject 需要特别注意这个问题。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值