专注Java教育14年 全国咨询/投诉热线:400-8080-105
动力节点LOGO图
始于2009,口口相传的Java黄埔军校
首页 hot资讯 浅谈Java序列化接口

浅谈Java序列化接口

更新时间:2020-10-29 17:39:49 来源:动力节点 浏览802次

 

Java接口是一系列方法的声明,是一些方法特征的集合,一个接口只有方法的特征没有方法的实现,因此这些方法可以在不同的地方被不同的类实现,而这些实现可以具有不同的行为(功能)。而序列化 (Serialization)是将对象的状态信息转换为可以存储或传输的形式的过程。Java序列化接口顾名思义,简单地说,就是可以将一个对象(标志对象的类型)及其状态转换为字节码,保存起来(可以保存在数据库,内存,文件等),然后可以在适当的时候再将其状态恢复(也就是反序列化)。


1 .Serializable接口

(1)serialization 不但可以在本机做,而且可以经由网络操作。它自动屏蔽了操作系统的差异,字节顺序等。比如,在 Windows 平台生成一个对象并序列化之,然后通过网络传到一台 Unix 机器上,然后可以在这台Unix机器上正确地重构(deserialization)这个对象。 不必关心数据在不同机器上如何表示,也不必关心字节的顺序或者其他任何细节。

另外,还应明白以下几点:

a. java.io.Serializable接口没有任何方法属性域,实现它的类只是从语义上表明自己是可以序列化的。

b. 在对一个 Serializable(可序列化)对象进行重新装配的过程中,不会调用任何构建器(甚至默认构建器)。整个对象都是通过从 InputStream 中取得数据恢复的。

c. 如是要一个类是可序列化的,那么它的子类也是可序列化的。

(2)serialVersionUID

serialVersionUID的取值是Java运行时环境根据类的内部细节自动生成的。如果对类的源代码作了修改,再重新编译,新生成的类文件的serialVersionUID的取值有可能也会发生变化。

类的serialVersionUID的默认值完全依赖于Java编译器的实现,对于同一个类,用不同的Java编译器编译,有可能会导致不同的serialVersionUID,也有可能相同。为了提高哦啊serialVersionUID的独立性和确定性,强烈建议在一个可序列化类中显示的定义serialVersionUID,为它赋予明确的值。显式地定义serialVersionUID有两种用途:

a. 在某些场合,希望类的不同版本对序列化兼容,因此需要确保类的不同版本具有相同的serialVersionUID;

b. 在某些场合,不希望类的不同版本对序列化兼容,因此需要确保类的不同版本具有不同的serialVersionUID。


2.自定义序列化

自定义序列化是由ObjectInput/OutputStream在序列化/反序列化时候通过反射检查该类是否存在以下方法(0个或多个):执行顺序从上往下,序列化调用1和2,反序列调用3和4;transient关键字当某个字段被声明为transient后,默认序列化机制就会忽略该字段。

1Object writeReplace() throws ObjectStreamException;可以通过此方法修改序列化的对象

2void writeObject(java.io.ObjectOutputStream out) throws IOException; 方法中调用defaultWriteObject() 使用writeObject的默认的序列化方式,除此之外可以加上一些其他的操作,如添加额外的序列化对象到输出:out.writeObject("XX")

3void readObject(java.io.ObjectInputStream in) throws Exception; 方法中调用defaultReadObject()使用readObject默认的反序列化方式,除此之外可以加上一些其他的操作,如读入额外的序列化对象到输入:in.readObject()

4Object readResolve() throws ObjectStreamException;可以通过此方法修改返回的对象

例子:单例模式的类实现序列化接口,若使用默认的序列化策略,则在反序列化返回的对象不符合单利模式(反射创建了新的对象,如下PersonSington对象),可以通过修改序列化的readResolve来实现自定义序列化返回结果来实现单例对象唯一(相当于1,2,3方法对4的结果毫无作用)。

public class PersonSingleton implements Serializable {

private static final long serialVersionUID = 1L;

private String name;

private PersonSingleton(String name) {

this.name = name;

};

private static PersonSingleton person = null;

public static synchronized PersonSingleton getInstance() {

if (person == null)

return person = new PersonSingleton("cgl");

return person;

}

private Object writeReplace() throws ObjectStreamException {

System.out.println("1 write replace start");

return this;//可修改为其他对象

}

private void writeObject(java.io.ObjectOutputStream out) throws IOException {

System.out.println("2 write object start");

out.defaultWriteObject();

//out.writeInt(1);

}

private void readObject(java.io.ObjectInputStream in) throws IOException, ClassNotFoundException {

System.out.println("3 read object start");

in.defaultReadObject();

//int i=in.readInt();

}

private Object readResolve() throws ObjectStreamException {

System.out.println("4 read resolve start");

return PersonSingleton.getInstance();//不管序列化的操作是什么,返回的都是本地的单例对象

}

public static void main(String[] args) throws Exception {

FileOutputStream out = new FileOutputStream(new File("D://person.dat"));

ObjectOutputStream op = new ObjectOutputStream(out);

op.writeObject(PersonSingleton.getInstance());

op.close();

FileInputStream in = new FileInputStream(new File("D://person.dat"));

ObjectInputStream oi = new ObjectInputStream(in);

Object person = oi.readObject();

in = new FileInputStream(new File("D://person.dat"));

oi = new ObjectInputStream(in);

PersonSinglton person1 = (PersonSinglton) oi.readObject();

System.out.println("sington person hashcode:" + person.hashCode());

System.out.println("sington person1 hashcode:" + person1.hashCode());

System.out.println("singleton getInstance hashcode:" + PersonSingleton.getInstance().hashCode());

System.out.println("singleton person equals:" + (person == PersonSingleton.getInstance()));

System.out.println("person equals1:" + (person1 == person));

}

}

运行结果:

write replace start

write object start

read object start

read resolve start

read object start

read resolve start

sington person hashcode:1550089733

sington person1 hashcode:1550089733

sington getInstance hashcode:1550089733

sington person equals:true

person equals1:true


3 Externalizable接口

Externalizable继承于Serializable,当使用该接口时,序列化的细节需要由程序员去完成。若writeExternal()与readExternal()方法未作任何处理,那么该序列化行为将不会保存/读取任何一个字段。出结果中所有字段的值均为空。

另外,若使用Externalizable进行序列化,当读取对象时,会调用被序列化类的无参构造器去创建一个新的对象,然后再将被保存对象的字段的值分别填充到新对象中。由于这个原因,实现Externalizable接口的类必须要提供一个无参的构造器,且它的访问权限为public。


以上就是为大家呕心沥血的整理的关于Java序列化接口的相关知识,相对于其他的Java接口知识点,Java序列化接口需要更多的时间去理解。观看本站的Java接口教程,结合其他的Java知识,贯彻其中,才能彻底掌握Java序列化接口。


提交申请后,顾问老师会电话与您沟通安排学习

免费课程推荐 >>
技术文档推荐 >>