| |
|
开发:
C++知识库
Java知识库
JavaScript
Python
PHP知识库
人工智能
区块链
大数据
移动开发
嵌入式
开发工具
数据结构与算法
开发测试
游戏开发
网络协议
系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程 数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁 |
-> Java知识库 -> 《Java基础知识》Java序列化与反序列化详解 -> 正文阅读 |
|
[Java知识库]《Java基础知识》Java序列化与反序列化详解 |
序列化的作用:为了不同jvm之间共享实例对象的一种解决方案.由java提供此机制。 序列化应用场景: 1. 分布式传递对象。 2. 网络传递对象。 3.?tomcat关闭以后会把session对象序列化到SESSIONS.ser文件中,等下次启动的时候就把这些session再加载到内存中。
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(); } } } 运行结果: 序列化相关注意事项: ??? 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 + '}'; } } 运行结果: 这个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 + '}'; } } 运行结果: 加入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(); } } } 运行结果: 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(); } } } 运行结果: Box类中实现readResolve() 方法可以实现单例对象还是同一个。 尚学堂给同学们带来全新的Java300集课程啦!java零基础小白自学Java必备优质教程_手把手图解学习Java,让学习成为一种享受_哔哩哔哩_bilibili |
|
|
上一篇文章 下一篇文章 查看所有文章 |
|
开发:
C++知识库
Java知识库
JavaScript
Python
PHP知识库
人工智能
区块链
大数据
移动开发
嵌入式
开发工具
数据结构与算法
开发测试
游戏开发
网络协议
系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程 数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁 |
360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 | -2024/11/23 17:08:12- |
|
网站联系: qq:121756557 email:121756557@qq.com IT数码 |