Java序列化(二)

    上文中实现了序列化和逆序列化一个简单的Name对象,下面来看一个稍复杂的情况,Name类中复合了其它类。        Name.java:

import java.io.Serializable;

/**
 * 可序列化的类,需要实现Serializable接口
 * @author 爽
 *
 */
public class Name implements Serializable {

	private static final long serialVersionUID = 1L;

	private String firstname;
	
	private String lastname;
	
	private Nickname nickname;
	
	public Name() {}

	public Name(String firstname, String lastname) {
		this.firstname = firstname;
		this.lastname = lastname;
	}
	
	public Name(String firstname, String lastname, Nickname nickname) {
		this.firstname = firstname;
		this.lastname = lastname;
		this.nickname = nickname;
	}

	public String getFirstname() {
		return firstname;
	}

	public void setFirstname(String firstname) {
		this.firstname = firstname;
	}

	public String getLastname() {
		return lastname;
	}

	public void setLastname(String lastname) {
		this.lastname = lastname;
	}
	
	public Nickname getNickname() {
		return nickname;
	}

	public void setNickname(Nickname nickname) {
		this.nickname = nickname;
	}

	@Override
	public String toString() {
		return "我的名字是" + firstname + "," + lastname + "\n我的昵称是" + nickname;
	}
	
}

       Nickname.java:

import java.io.Serializable;

/**
 * 昵称类
 * @author 爽
 *
 */
public class Nickname implements Serializable {

	private static final long serialVersionUID = 1L;
	
	private String name;
	
	public Nickname() {}

	public Nickname(String name) {
		this.name = name;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	@Override
	public String toString() {
		return name;
	}
	
}

       WriteObject.java:

import java.io.IOException;

import com.runqianapp.test.bean.Name;
import com.runqianapp.test.bean.Nickname;

public class WriteObject {

	public static void main(String[] args) throws IOException {
		Nickname nickname = new Nickname("黑曼巴");
		Name name = new Name("科比", "布莱恩特", nickname);
		Serializations.serialize(args[0], name);
	}

}

       运行后,指定目录下会生成相应文件,再次运行ReadObject.java,会得到如下输出信息:

我的名字是科比,布莱恩特
我的昵称是黑曼巴

       在序列化对象时,不仅会序列化当前对象本身,还会对该对象引用的其它对象也进行序列化,同样地,这些其它对象引用的另外对象也将被序列化,以此类推。在序列化过程中,可能会遇到不支持可序列化接口的对象,在此情况下,将抛出 NotSerializableException,并将标识不可序列化对象的类。如将Nickname.java去掉Serializable接口,再次运行WriteObject.java,会抛出如下异常:

Exception in thread "main" java.io.NotSerializableException: Nickname
	at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1180)
	at java.io.ObjectOutputStream.defaultWriteFields(ObjectOutputStream.java:1528)
	at java.io.ObjectOutputStream.writeSerialData(ObjectOutputStream.java:1493)
	at java.io.ObjectOutputStream.writeOrdinaryObject(ObjectOutputStream.java:1416)
	at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1174)
	at java.io.ObjectOutputStream.writeObject(ObjectOutputStream.java:346)
	at Serializations.serialize(Serializations.java:26)
	at WriteObject.main(WriteObject.java:13)

       我们可以用transient来修饰nickname属性,这样该类就可以正常序列化了,但是nickname中的属性也就无法序列化了,那我们如何让不能序列化的类NickName中的name属性可以序列化和反序列化呢?在序列化和反序列化过程中需要特殊处理的类必须使用下列准确签名来实现特殊方法:

private void writeObject(java.io.ObjectOutputStream out)
    throws IOException;
private void readObject(java.io.ObjectInputStream in)
    throws IOException, ClassNotFoundException;

       在对象序列化时,会调用writeObject方法,在对象反序列化时,会调用readObject方法。writeObject 方法负责写入特定类的对象的状态,以便相应的 readObject 方法可以还原它。通过调用 out.defaultWriteObject 可以调用保存 Object 的字段的默认机制。readObject 方法负责从流中读取并还原类字段。它可以调用 in.defaultReadObject 来调用默认机制,以还原对象的非静态和非瞬态字段。所以,我们可以在Name类中加入如下方法:

private void writeObject(java.io.ObjectOutputStream out)
		 throws IOException {
	// 默认序列化机制
	out.defaultWriteObject();
	// 序列化nickname中的name属性
	out.writeObject(nickname.getName());
}

private void readObject(java.io.ObjectInputStream in)
		 throws IOException, ClassNotFoundException {
	// 默认逆序列化机制
	in.defaultReadObject();
	// 逆序列化一个nickname对象
	nickname = new Nickname(in.readObject().toString());
}

       这样就可以处理其不可序列化的复合类Nickname中的name属性序列化及反序列化。运行WriteObject和ReadObject,序列化和反序列化成功。这两个方法如何实现取决于最终的需求,上面的例子是我想的一个比较符合应用场景的实例。

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏Java开发者杂谈

java序列化反序列化深入探究

When---什么时候需要序列化和反序列化: 简单的写一个hello world程序,用不到序列化和反序列化。写一个排序算法也用不到序列化和反序列化。但是当你想...

3429
来自专栏wannshan(javaer,RPC)

dubbo序列化过程源码分析

先看下dubbo在serialize层的类设计方案 序列化方案的入口,是接口Serialization的实现类。 /** * Serialization. ...

6219
来自专栏Spark学习技巧

Java transient关键字使用小记

1. transient的作用及使用方法 我们都知道一个对象只要实现了Serilizable接口,这个对象就可以被序列化,java的这种序列化模式为开发者提供了...

2876
来自专栏闵开慧

spark使用zipWithIndex和zipWithUniqueId为rdd中每条数据添加索引数据

spark的rdd中数据需要添加自增主键,然后将数据存入数据库,使用map来添加有的情况是可以的,有的情况是不可以的,所以需要使用以下两种中的其中一种来进行添加...

5869
来自专栏Golang语言社区

golang使用sort接口实现排序示例

今天看见群里再讨论排序的sort.Interface的实现,有童鞋一直搞不定,我就上手了一下,哦耶搞定了,代码放在这里. 其实很简单sort.Interface...

3597
来自专栏AI星球

Spark常用的算子以及Scala函数总结

首先,介绍一下scala语言: Scala 是一种把面向对象和函数式编程理念加入到静态类型语言中的混血儿。

4552
来自专栏微信公众号:Java团长

Java transient关键字使用小记

我们都知道一个对象只要实现了Serilizable接口,这个对象就可以被序列化,java的这种序列化模式为开发者提供了很多便利,我们可以不必关系具体序列化的过程...

912
来自专栏从零开始学自动化测试

Selenium2+python自动化42-判断元素(expected_conditions)

前言 经常有小伙伴问,如何判断一个元素是否存在,如何判断alert弹窗出来了,如何判断动态的元素等等一系列的判断,在selenium的expected_cond...

3607
来自专栏加米谷大数据

Spark RDD Map Reduce 基本操作

RDD是Spark中的抽象数据结构类型,任何数据在Spark中都被表示为RDD。从编程的角度来看,RDD可以简单看成是一个数组。和普通数组的区别是,RDD中的数...

1182
来自专栏个人分享

spark RDD transformation与action函数整理

3.过滤 filter 需要注意的是 filter并不会在原有RDD上过滤,而是根据filter的内容重新创建了一个RDD

1302

扫码关注云+社区