文档章节

Serializable详解

z
 zb1021
发布于 2017/09/07 18:19
字数 1786
阅读 9
收藏 0
点赞 0
评论 0

 

 

对象序列化是把一个对象转变为二进制数据流 的一种方法,而一个对象想要被序列化就需要实现Serializable接口。

查看Serializable接口的源码可以看到,并没有定义任何的方法,这是一个标识的接口:

public interface Serializable {
}

下面我们定义一个类

public class Person implements Serializable{
	/**
	 * 
	 */
	private static final long serialVersionUID = 1073458546087797538L;
	private String name;
	private int age;
	public Person(String name,int age){
		this.name=name;
		this.age=age;
	}
	public String toString(){
		return "姓名:"+this.name+":年龄"+this.age;
	}
}

这个类就实现了序列化的接口,可以看到在这个类里面我们定义了一个

serialVersionUID = 1073458546087797538L

一般来说,因为使用者jdk的不同,序列化和反序列化的版本不一致时就会出现异常,因此就加了这么一个常量来对版本一致性进行验证。如果在没有定义serialVersionUID时,java的序列化机制会默认的定义一个serialVersionUID值,下面是在serialVersion类中对serialVersionUID的详细介绍:

 * This readResolve method follows the same invocation rules and
 * accessibility rules as writeReplace.<p>
 *
 * The serialization runtime associates with each serializable class a version
 * number, called a serialVersionUID, which is used during deserialization to
 * verify that the sender and receiver of a serialized object have loaded
 * classes for that object that are compatible with respect to serialization.
 * If the receiver has loaded a class for the object that has a different
 * serialVersionUID than that of the corresponding sender's class, then
 * deserialization will result in an {@link InvalidClassException}.  A
 * serializable class can declare its own serialVersionUID explicitly by
 * declaring a field named <code>"serialVersionUID"</code> that must be static,
 * final, and of type <code>long</code>:
 *
 * <PRE>
 * ANY-ACCESS-MODIFIER static final long serialVersionUID = 42L;
 * </PRE>
 *
 * If a serializable class does not explicitly declare a serialVersionUID, then
 * the serialization runtime will calculate a default serialVersionUID value
 * for that class based on various aspects of the class, as described in the
 * Java(TM) Object Serialization Specification.  However, it is <em>strongly
 * recommended</em> that all serializable classes explicitly declare
 * serialVersionUID values, since the default serialVersionUID computation is
 * highly sensitive to class details that may vary depending on compiler
 * implementations, and can thus result in unexpected
 * <code>InvalidClassException</code>s during deserialization.  Therefore, to
 * guarantee a consistent serialVersionUID value across different java compiler
 * implementations, a serializable class must declare an explicit
 * serialVersionUID value.  It is also strongly advised that explicit
 * serialVersionUID declarations use the <code>private</code> modifier where
 * possible, since such declarations apply only to the immediately declaring
 * class--serialVersionUID fields are not useful as inherited members. Array
 * classes cannot declare an explicit serialVersionUID, so they always have
 * the default computed value, but the requirement for matching
 * serialVersionUID values is waived for array classes.
 *

大致上就是介绍需要一致,不一致会出现异常,而且必须是static,final,long。而这个值一致与否会对下面造成什么影响在下面我们继续写

而要完成对象的输入和输出,还需要使用对象输出流ObjectOutputStream和对象输入流ObjectInputStream,demo1进行输入

public class Demo1 {

	/**
	 * @param args
	 */
	public static void main(String[] args) throws IOException{
		// TODO 自动生成的方法存根
		File file=new File("d:"+File.separator+"test.txt");
		ObjectOutputStream oos=null;
		OutputStream out=new FileOutputStream(file);
		oos=new ObjectOutputStream(out);
		oos.writeObject(new Person("张三", 30));
		oos.close();
	}

}

输入数据以后,打开文件可以看到,记录的是一串二进制的乱码

demo2输出

public class Demo2 {

	/**
	 * @param args
	 */
	public static void main(String[] args) throws Exception{
		// TODO 自动生成的方法存根
		File file=new File("d:"+File.separator+"test.txt");
		InputStream input=new FileInputStream(file);
		ObjectInputStream objectInputStream=new ObjectInputStream(input);
		Object object=objectInputStream.readObject();
		objectInputStream.close();
		System.out.println(object);//姓名:张三:年龄30
	}

}

在两边的码一致的情况下,不会出现任何问题。我们把上面的uid最后一位去掉,运行程序就会出现下面的异常:

Exception in thread "main" java.io.InvalidClassException: test.Person; local class incompatible: stream classdesc serialVersionUID = 1073458546087797538, local class serialVersionUID = 107345854608779753

Serializable中所有的对象都必须被序列化,如果想进行部分序列化的话该怎么办?Externalizable接口是可以实现部分对象的序列化,这个接口定义了两个方法,writeExternal(ObjectOutput out)用来保存信息,readExternal(ObjectInput in)用来读取,反序列化对象。

public interface Externalizable extends java.io.Serializable {
    void writeExternal(ObjectOutput out) throws IOException;
    void readExternal(ObjectInput in) throws IOException, ClassNotFoundException;
}

在Externalizable接口接口中是必须要定义无参构造的,在其进行反序列化的时候会调用,否则就会出现异常。

import java.io.Externalizable;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectInputStream;
import java.io.ObjectOutput;
import java.io.ObjectOutputStream;

public class Person implements Externalizable {

	private static final long serialVersionUID = -842029427676826563L;

	public static String name;
	private int age;
	private transient int workDay = 5;
	private String fClub;

	public Person() {
        System.out.println("无参构造");
    }
	
	public Person(int age, String fClub) {
        this.age = age;
        this.fClub = fClub;
    }
	
	public int getAge() {
		return age;
	}

	public void setAge(int age) {
		this.age = age;
	}

	public int getWorkDay() {
		return workDay;
	}

	public void setWorkDay(int workDay) {
		this.workDay = workDay;
	}

	public String getfClub() {
		return fClub;
	}

	public void setfClub(String fClub) {
		this.fClub = fClub;
	}

	private void writeObject(ObjectOutputStream out) throws IOException {
		out.defaultWriteObject();//执行默认的序列化机制
		out.writeInt(workDay);
		System.out.println("正在进行序列持久化");
	}

	private void readObject(ObjectInputStream in) throws IOException,
			ClassNotFoundException {
		in.defaultReadObject();
		workDay = in.readInt();
		System.out.println("读取持久化对象");
	}

	@Override
	public void readExternal(ObjectInput arg0) throws IOException,
			ClassNotFoundException {
		// TODO Auto-generated method stub
	}

	@Override
	public void writeExternal(ObjectOutput arg0) throws IOException {
		// TODO Auto-generated method stub	
	} 
}
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;

public class Hello {

	public static void main(String[] args) {
		Person person = new Person(26, "Juventus");
		person.setWorkDay(7);
		try {
			FileOutputStream fs = new FileOutputStream("foo.ser");
			ObjectOutputStream os = new ObjectOutputStream(fs);
			os.writeObject(person);
			os.close();

			Person.name = "Alex";

			FileInputStream in = new FileInputStream("foo.ser");
			ObjectInputStream s = new ObjectInputStream(in);
			Person p = (Person) s.readObject();
			System.out.println("name==" + Person.name + " age==" + p.getAge()
					+ " workDay==" + p.getWorkDay() + " fClub==" + p.getfClub());
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
}

 

 输出结果

无参构造

name==Alex age==0 workDay==5 fClub==null  

可以看到,在Person p = (Person) s.readObject();这一步调用了无参构造person方法。而因为在foo.ser文件中只有类的类型声明,没有任何实例变量,所以Person对象中任何一个字段都没有被序列化,所以打印结果里面,age为0,fClub为null,而workDay为初始值5。writeExternal()与readExternal()方法未作任何处理,那么该序列化行为将不会保存/读取任何一个字段。

修改person类

package test;

import java.io.Externalizable;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectInputStream;
import java.io.ObjectOutput;
import java.io.ObjectOutputStream;

public class Person implements Externalizable {

	private static final long serialVersionUID = -842029427676826563L;

	public static String name;
	private int age;
	private transient int workDay = 5;
	private String fClub;

	public Person() {
        System.out.println("无参构造");
    }
	
	public Person(int age, String fClub) {
        this.age = age;
        this.fClub = fClub;
    }
	
	public int getAge() {
		return age;
	}

	public void setAge(int age) {
		this.age = age;
	}

	public int getWorkDay() {
		return workDay;
	}

	public void setWorkDay(int workDay) {
		this.workDay = workDay;
	}

	public String getfClub() {
		return fClub;
	}

	public void setfClub(String fClub) {
		this.fClub = fClub;
	}

	/*private void writeObject(ObjectOutputStream out) throws IOException {
		out.defaultWriteObject();//执行默认的序列化机制
		out.writeInt(workDay);
		System.out.println("正在进行序列持久化");
	}

	private void readObject(ObjectInputStream in) throws IOException,
			ClassNotFoundException {
		in.defaultReadObject();
		workDay = in.readInt();
		System.out.println("读取持久化对象");
	}*/

	 @Override  
	    public void writeExternal(ObjectOutput out) throws IOException {  
	        out.writeObject(fClub);  
	        out.writeInt(age);  
	        System.out.println("自定义序列化过程");  
	    }   
	      
	    @Override  
	    public void readExternal(ObjectInput in) throws IOException,  
	            ClassNotFoundException {  
	        fClub = (String) in.readObject();  
	        age = in.readInt();  
	        System.out.println("自定义反序列化");  
	    }   
}

结果:

自定义序列化过程
无参构造
自定义反序列化
name==Alex age==26 workDay==5 fClub==Juventus

当读取对象时,会调用被序列化类的无参构造器去创建一个新的对象,然后再将被保存对象的字段的值分别填充到新对象中。这就是为什么输出结果中会显示调动了无参构造器。由于这个原因,实现Externalizable接口的类必须要提供一个无参的构造器,且它的访问权限为public。

实现Externalizable接口是可以进行对象的部分序列化,但是其操作起来比serializable复杂麻烦,而使用serializable又会遇到例如在某些情况下我们会遇到密码等我们不希望被序列化的对象,这些信息对应的变量就可以加上transient关键字。换句话说,这个字段的生命周期仅存于调用者的内存中而不会写到磁盘里持久化。

觉得不错是可以点个赞。

© 著作权归作者所有

共有 人打赏支持
z
粉丝 1
博文 17
码字总数 9047
作品 0
石景山
程序员
JAP注释详解

1.设置Pojo为实体 @Entity //标识这个pojo是一个jpa实体 public class Users implements Serializable { } 2.设置表名 @Entity @Table(name = "users") //指定表名为users public class User......

Nemo ⋅ 2015/11/24 ⋅ 1

Java 序列化与反序列化

1.Java 序列化Serializable详解(附详细例子) http://www.2cto.com/kf/201405/305380.html 2.java.beans包里面有两个类XMLEncoder和XMLDecoder: http://blog.csdn.net/kingfox/article/deta......

当空皓月 ⋅ 2016/01/02 ⋅ 0

Android Bundle详解

1 Bundle介绍 Bundle主要用于传递数据;它保存的数据,是以key-value(键值对)的形式存在的。 我们经常使用Bundle在Activity之间传递数据,传递的数据可以是boolean、byte、int、long、float...

我叫leo- ⋅ 2016/04/11 ⋅ 0

读博文学Android

学习Android的过程中得到来自互联网上乐于分享和奉献的人们的帮助,这里收集了一些Android相关的知识点的介绍,研究,实践的博文地址。每篇文章将带给学习者更多的帮助,有些地址需要FQ的帮助...

secondriver ⋅ 2015/12/18 ⋅ 0

Android 命令 am 详解

位于frameworks/base/cmds/pm am命令作用:管理Activity usage: am [start|broadcast|instrument|profile] am start -D INTENT am broadcast INTENT am instrument [-r] [-e ] [-p ] [-w] am......

鉴客 ⋅ 2012/02/17 ⋅ 1

一篇文章,全面总结Android面试知识点

本篇文章的所有知识点是亲身经历十余家一二线互联网企业面试后总结产出,包含应聘Android开发岗位的各个方面的高频知识点,主要针对但不局限于Android应届面试。以下所有知识点都整理发布在G...

Ruheng ⋅ 2017/10/17 ⋅ 0

一篇文章,全面总结Android面试知识点

本篇文章的所有知识点是亲身经历十余家一二线互联网企业面试后总结产出,包含应聘Android开发岗位的各个方面的高频知识点,主要针对但不局限于Android应届面试。以下所有知识点都整理发布在G...

Ruheng ⋅ 2017/10/17 ⋅ 0

memcached的安装和使用

在Linux下安装运行memcache cd /tmp 可去官网获取相关版本链接 wget http://cloud.github.com/downloads/libevent/libevent/libevent-2.0.20-stable.tar.gztar -zxvf libevent-2.0.20-stable......

开源中国首席观察员 ⋅ 2012/10/30 ⋅ 0

MySQL事务隔离级别详解

SQL标准定义了4类隔离级别,包括了一些具体规则,用来限定事务内外的哪些改变是可见的,哪些是不可见的。低级别的隔离级一般支持更高的并发处理,并拥有更低的系统开销。 Read Uncommitted(...

偶是小娃 ⋅ 2014/03/31 ⋅ 0

MySQL事务隔离级别详解

SQL标准定义了4类隔离级别,包括了一些具体规则,用来限定事务内外的哪些改变是可见的,哪些是不可见的。低级别的隔离级一般支持更高的并发处理,并拥有更低的系统开销。 Read Uncommitted(...

风行韩国 ⋅ 2014/07/29 ⋅ 0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

构建自定义组件

#前言 接上篇,因项目需由H5转到小程序,故需打造自定义对话框。而这块需使用到微信小程序的自定义组件功能。 小程序自定义组件 点击此处,可以查看小程序自定义组件的api。 从自定义组件的样...

387 ⋅ 15分钟前 ⋅ 0

Maven 项目添加本地jar包的三种方式

Maven 项目添加本地jar包的三种方式 翻译自3 ways to add local jar to maven project [TOC] 简介 在构建 Maven 项目时,有时候需要导入本地的jar包,本文介绍了三种添加本地jar包的方法。 ...

Os_yxguang ⋅ 15分钟前 ⋅ 0

long超过16位之后浏览器自动截断问题处理。

java前后端交互的过程中,定义的Long字段超过16位之后,js发生截断,从而不能跟后台数据进行匹配。 处理方法 把long型字段转成string进行处理。(可以使用json注解转换或者springmvc统一拦截...

strict_nerd ⋅ 18分钟前 ⋅ 0

一文带你搞定Integer

1.1 前言 Integer是int对应的包装类,它包含一个int类型的字段存储数据,并提供了多个基本操作,能在 int 类型和 String 类型之间互相转换。在Java5中,引入了自动装箱和自动拆箱功能,Java可...

筱虾米 ⋅ 18分钟前 ⋅ 0

Linux kernel脉络和主干总结

写在前面 前人常说,对Linux操作系统/内核的理解,是计算机行业从业者的内功,决定了你在技术领域想走多远。但内核的庞大以及学习曲线之陡峭,总让我在学习途中觉得犹如“管中窥豹”。 随着工...

Markz0928 ⋅ 33分钟前 ⋅ 0

在gcc中使用intel风格的内联汇编

很简单,内联汇编使用asm(“.intel_syntax noprefix/n”)声明一下,以后的内联汇编就可以用intel风格了,构建可执行文件时给gcc加上-masm=intel参数。 先写一个小程序测试一下: [cpp] view...

simpower ⋅ 43分钟前 ⋅ 0

NIO 之 ByteBuffer实现原理

相关文章 BIO、NIO、AIO 内部原理分析 NIO 之 Selector实现原理 NIO 之 Channel实现原理 前言 Java NIO 主要由下面3部分组成: Buffer Channel Selector 在传统IO中,流是基于字节的方式进行...

轨迹_ ⋅ 52分钟前 ⋅ 0

Jenkins docker权限问题

环境Ubuntu Server 工具 jenkins-war:2.89.2 报错信息 Cannot connect to the Docker daemon. Is the docker daemon running on this host?Build step 'Execute shell' marked build as fai......

Pulsar-V ⋅ 53分钟前 ⋅ 0

180621-一个简单的时间窗口设计与实现

如何设计一个计数的时间窗口 时间窗口,通常对于一些实时信息展示中用得比较多,比如维持一个五分钟的交易明细时间窗口,就需要记录当前时间,到五分钟之前的所有交易明细,而五分钟之前的数...

小灰灰Blog ⋅ 今天 ⋅ 0

Android之Dalvik、ART、JIT、AOT

Android之Dalvik、ART、JIT、AOT 本文内容:Dalvik、ART、JIT、AOT之间关系 本文定位:知识记录 学习过程记录,加深理解,提升文字组合表达能力。也希望能给学习的同学一些灵感 本文整理于[...

lichuangnk ⋅ 今天 ⋅ 0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

返回顶部
顶部