首页 技术 正文
技术 2022年11月22日
0 收藏 726 点赞 2,460 浏览 7538 个字

序列化的作用:为了不同jvm之间共享实例对象的一种解决方案.由java提供此机制。

序列化应用场景:

1. 分布式传递对象。

2. 网络传递对象。

3. tomcat关闭以后会把session对象序列化到SESSIONS.ser文件中,等下次启动的时候就把这些session再加载到内存中。

完整案例:

import java.io.Serializable;public class Box implements Serializable {    public Box(){
System.out.println("调用构造Box方法");
} private String width;
private String height; public String getWidth() {
return width;
} public void setWidth(String width) {
this.width = width;
} public String getHeight() {
return height;
} public void setHeight(String height) {
this.height = height;
} @Override
public String toString() {
return "Box{" +
"width=" + width +
", height=" + height +
'}';
}
}
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;public class SerializableDemo {
public static void main(String[] args){
Box myBox = new Box();
myBox.setWidth("50");
myBox.setHeight("30"); try{
File file = new File("src\\demo\\knowledgepoints\\file\\foo.ser"); //把对象信息写入文件中。
ObjectOutputStream oout = new ObjectOutputStream (new FileOutputStream(file));
oout.writeObject(myBox);
oout.close(); //把对象信息从文件中获取出来。
ObjectInputStream oin = new ObjectInputStream(new FileInputStream(file));
Box newMyBox = (Box)oin.readObject(); // 没有强制转换到Person类型
oin.close();
System.out.println(newMyBox);
}catch(Exception ex){
ex.printStackTrace();
}
}
}

运行结果:

《Java基础知识》序列化与反序列化详解

序列化相关注意事项:

a)序列化时,只对对象的状态进行保存,而不管对象的方法;

b)当一个父类实现序列化,子类自动实现序列化,不需要显式实现Serializable接口;

c)当一个对象的实例变量引用其他对象,序列化该对象时也把引用对象进行序列化;

d)  被序列化的对象需要 实现(Serializable)接口;

e) 案例:构造方法没有执行,说明生成新对象,不是通过New出来的;

Java 对象被序列化需要实现(Serializable)接口,原因:

在 我们将对象序列化的类 ObjectOutputStream 的方法 writeObject0 中可以找到答案。

以下是JDK8的部分源码,红色字体部分就是原因。

private void writeObject0(Object obj, boolean unshared)
throws IOException
{
boolean oldMode = bout.setBlockDataMode(false);
depth++;
try {
// handle previously written and non-replaceable objects
int h;
if ((obj = subs.lookup(obj)) == null) {
writeNull();
return;
} else if (!unshared && (h = handles.lookup(obj)) != -1) {
writeHandle(h);
return;
} else if (obj instanceof Class) {
writeClass((Class) obj, unshared);
return;
} else if (obj instanceof ObjectStreamClass) {
writeClassDesc((ObjectStreamClass) obj, unshared);
return;
} // check for replacement object
Object orig = obj;
Class<?> cl = obj.getClass();
ObjectStreamClass desc;
for (;;) {
// REMIND: skip this check for strings/arrays?
Class<?> repCl;
desc = ObjectStreamClass.lookup(cl, true);
if (!desc.hasWriteReplaceMethod() ||
(obj = desc.invokeWriteReplace(obj)) == null ||
(repCl = obj.getClass()) == cl)
{
break;
}
cl = repCl;
}
if (enableReplace) {
Object rep = replaceObject(obj);
if (rep != obj && rep != null) {
cl = rep.getClass();
desc = ObjectStreamClass.lookup(cl, true);
}
obj = rep;
} // if object replaced, run through original checks a second time
if (obj != orig) {
subs.assign(orig, obj);
if (obj == null) {
writeNull();
return;
} else if (!unshared && (h = handles.lookup(obj)) != -1) {
writeHandle(h);
return;
} else if (obj instanceof Class) {
writeClass((Class) obj, unshared);
return;
} else if (obj instanceof ObjectStreamClass) {
writeClassDesc((ObjectStreamClass) obj, unshared);
return;
}
} // remaining cases
if (obj instanceof String) {
writeString((String) obj, unshared);
} else if (cl.isArray()) {
writeArray(obj, desc, unshared);
} else if (obj instanceof Enum) {
writeEnum((Enum<?>) obj, desc, unshared);
} else if (obj instanceof Serializable) {
writeOrdinaryObject(obj, desc, unshared);
} else {
if (extendedDebugInfo) {
throw new NotSerializableException(
cl.getName() + "\n" + debugInfoStack.toString());
} else {
throw new NotSerializableException(cl.getName());
}
}
} finally {
depth--;
bout.setBlockDataMode(oldMode);
}
}

如何将序列化控制在自己手中?

1. 通过关键字【transient】实现,字段值不被序列化。

改一下Box类:

import java.io.Serializable;public class Box implements Serializable {    public Box(){
System.out.println("调用构造Box方法");
} // 关键字:transient 控制width不被序列化,保护数据。
private transient String width;
private String height; public String getWidth() {
return width;
} public void setWidth(String width) {
this.width = width;
} public String getHeight() {
return height;
} public void setHeight(String height) {
this.height = height;
} @Override
public String toString() {
return "Box{" +
"width=" + width +
", height=" + height +
'}';
}
}

运行结果:

《Java基础知识》序列化与反序列化详解

这个box的width值被擦除了。

2. writeObject()方法与readObject()方法。

import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;public class Box implements Serializable { public Box(){
System.out.println("调用构造Box方法");
} // 关键字:transient 控制width不被序列化,保护数据。
private transient String width;
private String height; public String getWidth() {
return width;
} public void setWidth(String width) {
this.width = width;
} public String getHeight() {
return height;
} public void setHeight(String height) {
this.height = height;
} private void writeObject(ObjectOutputStream out) throws IOException {
out.defaultWriteObject();
out.writeChars(width);
} private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
in.defaultReadObject();
width = in.readLine();
} @Override
public String toString() {
return "Box{" +
"width=" + width +
", height=" + height +
'}';
}
}

运行结果:

《Java基础知识》序列化与反序列化详解

加入writeObject()方法与readObject()方法后,width值又回来了,这两个方法都是私有的,已经可以基本猜测是通过反射调用方法,赋值的。

3.Externalizable 接口,自定义实现写入和读取序列化对象

import java.io.Externalizable;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;public class BoxTmp implements Externalizable {
public BoxTmp(){
System.out.println("调用构造Box方法");
} private String width;
private String height; public String getWidth() {
return width;
} public void setWidth(String width) {
this.width = width;
} public String getHeight() {
return height;
} public void setHeight(String height) {
this.height = height;
} @Override
public void writeExternal(ObjectOutput out) throws IOException {
out.writeChars(width+","+width);
} @Override
public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
String str = in.readLine();
this.width = str.split(",")[0];
this.height = str.split(",")[1];
} @Override
public String toString() {
return "BoxTmp{" +
"width='" + width + '\'' +
", height='" + height + '\'' +
'}';
}
}
public class ExternalizableDemo {
public static void main(String[] args){
BoxTmp boxTmp = new BoxTmp();
boxTmp.setWidth("50");
boxTmp.setHeight("30"); try{
File file = new File("src\\demo\\knowledgepoints\\file\\foo.txt"); //把对象信息写入文件中。
ObjectOutputStream oout = new ObjectOutputStream (new FileOutputStream(file));
oout.writeObject(boxTmp);
oout.close(); //把对象信息从文件中获取出来。
ObjectInputStream oin = new ObjectInputStream(new FileInputStream(file));
BoxTmp newBoxTmp = (BoxTmp)oin.readObject(); // 没有强制转换到Person类型
oin.close();
System.out.println(newBoxTmp);
}catch(Exception ex){
ex.printStackTrace();
}
}
}

运行结果:

《Java基础知识》序列化与反序列化详解

Externalizable接口中的writeExternal和readExternal 方法可以用来自定义实现值的传递,覆盖等其他操作。

同时构造方法被执行了,说明这个类是被new出来后,由你支配。

4. readResolve()方法

import java.io.ObjectStreamException;
import java.io.Serializable;public class Box implements Serializable { public static Box box = new Box(); public Box(){} public Box(String height,String width){
this.height = height;
this.width = width;
} public static Box getInstance() {
if(box == null){
box = new Box("20","10");
}
return box;
} private String width;
private String height; public String getWidth() {
return width;
} public void setWidth(String width) {
this.width = width;
} public String getHeight() {
return height;
} public void setHeight(String height) {
this.height = height;
} private Object readResolve() throws ObjectStreamException {
return Box.box;
}
}
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;public class SerializableDemo {
public static void main(String[] args){
Box myBox = Box.getInstance();
try{
File file = new File("src\\demo\\knowledgepoints\\file\\foo.ser"); //把对象信息写入文件中。
ObjectOutputStream oout = new ObjectOutputStream (new FileOutputStream(file));
oout.writeObject(myBox);
oout.close(); //把对象信息从文件中获取出来。
ObjectInputStream oin = new ObjectInputStream(new FileInputStream(file));
Box newMyBox = (Box)oin.readObject(); // 没有强制转换到Person类型
oin.close();
System.out.println("newMyBox == myBox : "+(newMyBox == myBox));
}catch(Exception ex){
ex.printStackTrace();
}
}
}

运行结果:

《Java基础知识》序列化与反序列化详解

Box类中实现readResolve() 方法可以实现单例对象还是同一个。

参考资料

https://www.cnblogs.com/qq3111901846/p/7894532.html

相关推荐
python开发_常用的python模块及安装方法
adodb:我们领导推荐的数据库连接组件bsddb3:BerkeleyDB的连接组件Cheetah-1.0:我比较喜欢这个版本的cheeta…
日期:2022-11-24 点赞:878 阅读:9,104
Educational Codeforces Round 11 C. Hard Process 二分
C. Hard Process题目连接:http://www.codeforces.com/contest/660/problem/CDes…
日期:2022-11-24 点赞:807 阅读:5,581
下载Ubuntn 17.04 内核源代码
zengkefu@server1:/usr/src$ uname -aLinux server1 4.10.0-19-generic #21…
日期:2022-11-24 点赞:569 阅读:6,428
可用Active Desktop Calendar V7.86 注册码序列号
可用Active Desktop Calendar V7.86 注册码序列号Name: www.greendown.cn Code: &nb…
日期:2022-11-24 点赞:733 阅读:6,200
Android调用系统相机、自定义相机、处理大图片
Android调用系统相机和自定义相机实例本博文主要是介绍了android上使用相机进行拍照并显示的两种方式,并且由于涉及到要把拍到的照片显…
日期:2022-11-24 点赞:512 阅读:7,835
Struts的使用
一、Struts2的获取  Struts的官方网站为:http://struts.apache.org/  下载完Struts2的jar包,…
日期:2022-11-24 点赞:671 阅读:4,918