JAVA IO 序列化与设计模式
序列化
什么是序列化
序列化:保存对象的状态
反序列化:读取保存对象的状态
序列化和序列化是Java提供的一种保存恢复对象状态的机制
序列化有什么用
将数据保存到文件或数据库中时
将数据通过套接字在网络上传输时
通过 RPC RMI等传输对象时
如何序列化
实现Serializable接口
实现Externalizable接口
serialVersionUID的作用serialVersionUID建议给一个确定的值,不要由系统自动生成,否则在增减字段(不能修改字段类型及长度)时,如果两边的类的版本不同会导致反序列化失败
默认序列化机制
如果仅仅只是让某个类实现Serializable接口,而没有其它任何处理的话,则就是使用默认序列化机制。使用默认机制,在序列化对象时,不仅会序列化当前对象本身,还会对该对象引用的其它对象也进行序列化,同样地,这些其它对象引用的另外对象也将被序列化,以此类推。所以,如果一个对象包含的成员变量是容器类对象,而这些容器所含有的元素也是容器类对象,那么这个序列化的过程就会较复杂,开销也较大。
(01) 序列化对static和transient变量,是不会自动进行状态保存的。
transient的作用就是,用transient声明的变量,不会被自动序列化。
(02) 对于Socket, Thread类,不支持序列化。若实现序列化的接口中,有Thread成员;在对该类进行序列化操作时,运行会出错。
这主要是基于资源分配方面的原因。如果Socket,Thread类可以被序列化,但是被反序列化之后也无法对他们进行重新的资源分配。
示例:
package ioEx;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;
public class Serial {
private static final String TMP_FILE = "text.txt";
public static void main(String[] args) {
testWrite();
testRead();
}
private static void testWrite() {
try {
ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream(TMP_FILE));
AnObject box = new AnObject(1, 1, "1");
out.writeObject(box);
out.writeBoolean(true);
out.writeByte((byte)65);
out.writeChar('a');
out.writeInt(20160415);
out.writeFloat(3.14F);
out.writeDouble(Math.PI);
HashMap<String,String> map = new HashMap<String,String>();
map.put("a", "a");
map.put("b", "b");
map.put("c", "c");
out.writeObject(map);
out.close();
} catch (Exception ex) {
ex.printStackTrace();
}
}
private static void testRead() {
try {
ObjectInputStream in = new ObjectInputStream(new FileInputStream(TMP_FILE));
AnObject box = (AnObject) in.readObject();
System.out.println("testWrite box: " + box);
System.out.println("boolean:"+ in.readBoolean());
System.out.println("byte:" + (in.readByte()&0xff));
System.out.println("char:" + in.readChar());
System.out.println("int:" + in.readInt());
System.out.println("float:" + in.readFloat());
System.out.println("double:" + in.readDouble());
// 读取HashMap对象
HashMap<String,String> map = (HashMap<String,String>) in.readObject();
Iterator<Entry<String, String>> iter = map.entrySet().iterator();
while (iter.hasNext()) {
Map.Entry<String,String> entry = (Entry<String, String>)iter.next();
System.out.println(entry.getKey()+"--"+ entry.getValue());
}
in.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
class AnObject implements Serializable { private int obja;
private int objb;
private String objc;
private static int statica;
private transient int transienda; //必须用static或transient修饰才可能序列化,否则运行报错
private static transient Thread thread = new Thread() {
@Override
public void run() {
System.out.println("Serializable");
}
}; public AnObject(int obja, int objb, String objc) {
this.obja = obja;
this.objb = objb;
this.objc = objc;
this.statica=obja;
this.transienda=obja;
} //如果要使transient序列化要重写writeObject,和readObject 方法
// private void writeObject(ObjectOutputStream out) throws IOException{
// out.defaultWriteObject();
// out.writeInt(transienda);
// }
//
// private void readObject(ObjectInputStream in) throws IOException,ClassNotFoundException{
// in.defaultReadObject();
// transienda = in.readInt();
// } @Override
public String toString() {
return "obja:"+obja+","+ "objb:"+objb+","+ "objc:"+objc+","+ "statica:"+statica+","+ "transienda:"+transienda;
}
}
JAVA IO的设计模式
JAVA IO框架主要使用的两种设计模式 装饰模式和适配器模式
装饰模式又名包装(Wrapper)模式
装饰模式以对客户端透明的方式扩展对象的功能,是继承关系的一个替代方案。
装饰模式通过创建一个包装对象,也就是装饰,来包裹真实的对象。
装饰模式以对客户端透明的方式动态地给一个对象附加上更多的责任。换言之,客户端并不会觉得对象在装饰前和装饰后有什么不同。
装饰模式可以在不创造更多子类的情况下,将对象的功能加以扩展。
装饰模式把客户端的调用委派到被装饰类。装饰模式的关键在于这种扩展是完全透明的。
装饰模式的角色
抽象构件角色(Component):给出一个抽象接口,以规范准备接收附加责任的对象。
具体构件角色(Concrete Component):定义将要接收附加责任的类。
装饰角色(Decorator):持有一个构件(Component)对象的引用,并定义一个与抽象构件接口一致的接口。
具体装饰角色(Concrete Decorator):负责给构件对象“贴上”附加的责任。
装饰模式的特点
装饰对象和真实对象有相同的接口。这样客户端对象就可以以和真实对象相同的方式和装饰对象交互。
装饰对象包含一个真实对象的引用(reference)。
装饰对象接收所有来自客户端的请求,它把这些请求转发给真实的对象。
装饰对象可以在转发这些请求之前或之后附加一些功能。
这样就确保了在运行时,不用修改给定对象的结构就可以在外部增加附加的功能。
示例:
package Test;
public class Wrapper {
public static void main(String[] args) {
Component c = new RealizeComponent();
Component c1 = new RealizeDecorator1(c);
c1.say();
System.out.println("--");
Component c2 = new RealizeDecorator2(c1);
c2.say();
}
}
interface Component{
public void say();
}
class RealizeComponent implements Component{
@Override
public void say() {
System.out.println("A");
}
}
class Decorator implements Component{
private Component component;
public Decorator(Component component) {
this.component = component;
}
@Override
public void say(){
component.say();
}
}
class RealizeDecorator1 extends Decorator{
public RealizeDecorator1(Component component){
super(component);
}
@Override
public void say(){
super.say();
this.sayAnother();
}
private void sayAnother(){
System.out.println("B");
}
}
class RealizeDecorator2 extends Decorator{
public RealizeDecorator2(Component component){
super(component);
}
@Override
public void say(){
super.say();
this.sayAnother();
}
private void sayAnother(){
System.out.println("C");
}
}
装饰模式的优点
装饰模式与继承关系的目的都是要扩展对象的功能,但是装饰模式可以提供比继承更多的灵活性。装饰模式允许系统动态决定“贴上”一个需要的“装饰”,或者除掉一个不需要的“装饰”。继承关系则不同,继承关系是静态的,它在系统运行前就决定了。
通过使用不同的具体装饰类以及这些装饰类的排列组合,设计师可以创造出很多不同行为的组合。
装饰模式的缺点
由于使用装饰模式,可以比使用继承关系需要较少数目的类。使用较少的类,当然使设计比较易于进行。但是,在另一方面,使用装饰模式会产生比使用继承关系更多的对象。更多的对象会使得查错变得困难,特别是这些对象看上去都很相像。
JAVA IO中的装饰模式
抽象构件(Component)角色:由InputStream扮演。这是一个抽象类,为各种子类型提供统一的接口。
具体构件(ConcreteComponent)角色:由ByteArrayInputStream、FileInputStream、PipedInputStream、StringBufferInputStream等类扮演。它们实现了抽象构件角色所规定的接口。
抽象装饰(Decorator)角色:由FilterInputStream扮演。它实现了InputStream所规定的接口。
具体装饰(ConcreteDecorator)角色:由几个类扮演,分别是BufferedInputStream、DataInputStream以及两个不常用到的类LineNumberInputStream、PushbackInputStream。
适配器模式

上图是适配器模式的类图。Adapter 适配器设计模式中有 3 个重要角色:被适配者 Adaptee,适配器 Adapter 和目标对象 Target。其中两个现存的想要组合到一起的类分别是被适配者 Adaptee 和目标对象 Target 角色,按照类图所示,我们需要创建一个适配器 Adapter 将其组合在一起。
最简单的适配器示例:
package AdapterEx;
class Apple {
public void getAColor(String str) {
System.out.println("Apple color is: " + str);
}
}
class Orange {
public void getOColor(String str) {
System.out.println("Orange color is: " + str);
}
}
class AppleAdapter extends Apple {
private Orange orange;
public AppleAdapter(Orange orange) {
this.orange = orange;
}
public void getAColor(String str) {
orange.getOColor(str);
}
}
public class AdapterEx {
public static void main(String[] args) {
Apple apple = new Apple();
apple.getAColor("green");
Orange orange = new Orange();
AppleAdapter aa = new AppleAdapter(orange);
aa.getAColor("red");
}
}
Java I/O 库大量使用了适配器模式,例如 ByteArrayInputStream 是一个适配器类,它继承了 InputStream 的接口,并且封装了一个 byte 数组。换言之,它将一个 byte 数组的接口适配成 InputStream 流处理器的接口。
我们知道 Java 语言支持四种类型:Java 接口,Java 类,Java 数组,原始类型(即 int,float 等)。前三种是引用类型,类和数组的实例是对象,原始类型的值不是对象。也即,Java 语言的数组是像所有的其他对象一样的对象,而不管数组中所存储的元素类型是什么。这样一来的话,ByteArrayInputStream 就符合适配器模式的描述,是一个对象形式的适配器类。FileInputStream 是一个适配器类。在 FileInputStream 继承了 InputStrem 类型,同时持有一个对 FileDiscriptor 的引用。这是将一个 FileDiscriptor 对象适配成 InputStrem 类型的对象形式的适配器模式。
同样地,在 OutputStream 类型中,所有的原始流处理器都是适配器类。ByteArrayOutputStream 继承了 OutputStream 类型,同时持有一个对 byte 数组的引用。它一个 byte 数组的接口适配成 OutputString 类型的接口,因此也是一个对象形式的适配器模式的应用。
FileOutputStream 继承了 OutputStream 类型,同时持有一个对 FileDiscriptor 对象的引用。这是一个将 FileDiscriptor 接口适配成 OutputStream 接口形式的对象型适配器模式。
Reader 类型的原始流处理器都是适配器模式的应用。StringReader 是一个适配器类,StringReader 类继承了 Reader 类型,持有一个对 String 对象的引用。它将 String 的接口适配成 Reader 类型的接口。
装饰模式和适配器模式的对比
(1)装饰模式和适配器模式,都是通过封装其他对象达到设计目的的。
(2)理想的装饰模式在对被装饰对象进行功能增强时,要求具体构件角色、装饰角色的接口与抽象构件角色的接口完全一致;而适配器模式则不然,一般而言,适配器模式并不要求对源对象的功能进行增强,只是利用源对象的功能而已,但是会改变源对象的接口,以便和目标接口相符合。
(3)装饰模式有透明和半透明两种,区别就在于接口是否完全一致。关于装饰模式的重要的事实是,很难找到理想的装饰模式。一般而言,对一个对象进行功能增强的同时,都会导致加入新的行为,因此,装饰角色的接口比抽象构件角色的接口宽是很难避免的,这种现象存在于Java I/O库中多有的类型的链接流处理器中。一个装饰类提供的新的方法越多,它离纯装饰模式的距离就越远,离适配器模式的距离也就越近。
原文链接:http://blog.tingyun.com/web/article/detail/460
JAVA IO 序列化与设计模式的更多相关文章
- Java IO: 序列化与ObjectInputStream、ObjectOutputStream
作者:Jakob Jenkov 译者: 李璟(jlee381344197@gmail.com) 本小节会简要概括Java IO中的序列化以及涉及到的流,主要包括ObjectInputStream和O ...
- JAVA IO中的设计模式
在java语言 I/O库的设计中,使用了两个结构模式,即装饰模式和适配器模式. 在任何一种计算机语言中,输入/输出都是一个很重要的部分.与一般的计算机语言相比,java将输入/输出的功能和 ...
- 基于Java IO 序列化方案的memcached-session-manager多memcached节点配置
在公司项目里想要在前端通过nginx将请求负载均衡,而后台的几组tomcat的session通过memcached(non-sticky模式)进行统一管理,这几组tomcat部署的web app是同一 ...
- Java IO教程
1 Java IO 教程 2 Java IO 概述 3 Java IO: 文件 4 Java IO: 管道 5 Java IO: 网络 6 Java IO: 字节和字符数组 7 Java IO: S ...
- Java IO和NIO文章目录
1.java IO详尽解析 2.深入分析 Java I/O 的工作机制 3.InputStream类详解 4.OutputStream类详解 5.JAVA的节点流和处理流 6.FileInputStr ...
- Java IO 学习总结 学习手册总结
Java IO 是一套Java用来读写数据(输入和输出)的API.大部分程序都要处理一些输入,并由输入产生一些输出.Java为此提供了java.io包. 代码 github地址:https://git ...
- java之序列化
详细内容 连接https://blog.csdn.net/qq_27093465/article/details/78544505 Java 之 Serializable 序列化和反序列化的概念,作用 ...
- Java之序列化和反序列化
序列化的对象: package test_demo.SerializableOper; import java.io.Serializable; /* * 序列化对象需要实现序列号接口 * */ pu ...
- 高级Java工程师必备 ----- 深入分析 Java IO (三)
概述 Java IO即Java 输入输出系统.不管我们编写何种应用,都难免和各种输入输出相关的媒介打交道,其实和媒介进行IO的过程是十分复杂的,这要考虑的因素特别多,比如我们要考虑和哪种媒介进行IO( ...
随机推荐
- 基于HTML5 WebGL实现3D飞机叶轮旋转
在上一篇<基于HT for Web矢量实现2D叶轮旋转>中讲述了叶轮旋转在2D拓扑上的应用,今天我们就来讲讲叶轮旋转在3D上的应用. 在3D拓扑上可以创建各种各样的图元,在HT for W ...
- MyEclipse中常用的快捷键大全,快来.....
在这里分享点常用的快捷键,希望对你有帮助! Eclipse的编辑功能非常强大,掌握了Eclipse快捷键功能,能够大大提高开发效率.Eclipse中有如下一些和编辑相关的快捷键. 1. [ALT+/] ...
- Socket开发框架之数据加密及完整性检查
在前面两篇介绍了Socket框架的设计思路以及数据传输方面的内容,整个框架的设计指导原则就是易于使用及安全性较好,可以用来从客户端到服务端的数据安全传输,那么实现这个目标就需要设计好消息的传输和数据加 ...
- 【SQL】分配函数一枚[AllotToTable]
适用环境:MSSQL 2005+.其中05需修改部分语句的写法才行,如: --变量的声明和赋值需分开写 --需改为如下 --05不支持+=这样的复合运算符 --需改为如下 功能: 将一个数字(整数或有 ...
- QTableWidget的美化
FriendTable->setFrameShape(QFrame::NoFrame); //设置边框 FriendTable->setHorizontalHeaderLabels( ...
- C#的变迁史 - C# 4.0 之并行处理篇
前面看完了Task对象,这里再看一下另一个息息相关的对象Parallel. Parallel对象 Parallel对象封装了能够利用多核并行执行的多线程操作,其内部使用Task来分装多线程的任务并试图 ...
- hibernate简单注释(一.1)
**************************************************************************************************** ...
- html+jquery翻页相册(原创)
呵呵 今天心情大好,再发一篇最进前端实现的相册模仿功能 这个相册是在一个网站的案例展示页面上实现的,没单独写出来,没时间,重用性也很差,以后有时间了再单独提取出来, 写这个玩意前,我在网上找了一些案例 ...
- Enum 枚举小结 java **** 最爱那水货
import java.util.HashMap; import java.util.Map; /** * 收单行 大写首字母 和对应的编码<br/> * * ABC 农业银行<br ...
- Virtual Box和Linux的网络配置盲记
近来可能在虚拟机重装了Linux的缘故,在用yum安装软件时出现错误,在提示上连接镜像网站时,都是"linux counldn't resolve host"这样的提示.我估计是l ...