深入了解序列化“契约”
由于Java提供了良好的默认支持,实现基本的对象序列化是件比较简单的事。待序列化的Java类只需要实现Serializable接口即可。Serializable仅是一个标记接口,并不包含任何需要实现的具体方法。实现该接口只是为了声明该Java类的对象是可以被序列化的。实际的序列化和反序列化工作是通过ObjectOuputStream和ObjectInputStream来完成的。ObjectOutputStream的writeObject方法可以把一个Java对象写入到流中,ObjectInputStream的readObject方法可以从流中读取一个Java对象。在写入和读取的时候,虽然用的参数或返回值是单个对象,但实际上操纵的是一个对象图,包括该对象所引用的其它对象,以及这些对象所引用的另外的对象。Java会自动帮你遍历对象图并逐个序列化.
在通过ObjectInputStream的readObject方法读取到一个对象之后,这个对象是一个新的实例,但是其构造方法是没有被调用的,其中的域的初始化代码也没有被执行。对于那些没有被序列化的域,在新创建出来的对象中的值都是默认的.
把一个Java对象序列化之后,所得到的字节数组一般会保存在磁盘或数据库之中跨JVM使用。反序列化的时候不能仅根据Java类的全名来判断,这个类可能处于另外一个JVM,而当前JVM中可能存在名称相同,但是含义完全不同的Java类。这个对应关系是通过一个全局惟一标识符serialVersionUID来实现的。通过在实现了Serializable接口的类中定义该域,就声明了该Java类的一个惟一的序列化版本号。JVM会比对从字节数组中得出的类的版本号,与JVM中查找到的类的版本号是否一致,来决定两个类是否是兼容的。对于开发人员来说,需要记得的就是在实现了Serializable接口的类中定义这样的一个域,并在版本更新过程中保持该值不变。当然,如果不希望维持这种向后兼容性,换一个版本号即可。该域的值一般是综合Java类的各个特性而计算出来的一个哈希值,可以通过Java提供的serialver命令来生成。
虽然一个对象要序列化,只需要实现一个没有任何方法的接口Serializable,但是,深入研究你会发现,java序列化其实包含很多不符合java语法规则的"契约",或者说这些实现不是通过常规java实现的,推测应该是通过反射实现的,因此成为契约。
1.要把一些域不序列化,可以在器前边加上关键字"trasient",这个容易理解。
2.只把部分域序列化,可以在类中声明一个固定域名和类型的静态字段,这个就诡异了
private static final ObjectStreamField[] serialPersistentFields = { new ObjectStreamField("firstName", String.class) };
3.如果要深度修改序列化过程,可以在类中实现writeObject和readObject方法,奇怪的是,这两个方法既不是Object的方法,也不是Serializable的方法,但是他就是被ObjectInputStream和ObjectOutputStream调用了,应该是通过反射,这也是"契约"的一部分,如下(这两个方法需要在要序列化的类中实现):
private void writeObject(ObjectOutputStream output) throws IOException {
output.defaultWriteObject();
output.writeUTF("Hello World");
}
private void readObject(ObjectInputStream input) throws IOException,
ClassNotFoundException {
input.defaultReadObject();
String value = input.readUTF();
System.out.println(value);
}
4.更离奇的契约还有,如果我们一个订单包含客户信息,但是我们不想序列化客户全部信息,而客户类又不能改动,这样,我们需要创建一个类来代替订单类,我们的实现如下:
private static class OrderReplace implements Serializable {// 创建一个新的类用来代替Order
private static final long serialVersionUID = 4654546423735192613L;
private String orderId;
public OrderReplace(Order order) {
this.orderId = order.getId();
}
private Object readResolve() throws ObjectStreamException {// 契约方法,用来读取时重新组装对象
// 根据orderId查找Order对象并返回
}
}
private Object writeReplace() throws ObjectStreamException {// 契约方法,更WriteObject不同,可以替换对象
return new OrderReplace(this);
}
}
/**************************************************************************/
/**************************************************************************/
RMI:
RMI(Remote Method Invocation)是Java中的远程过程调用(Remote Procedure Call,RPC)实现,是一种分布式Java应用的实现方式。
RMI采用的是典型的客户端-服务器端架构。首先需要定义的是服务器端的远程接口,只需要继承自RMI中的Remote接口即可。Remote和Serializable一样,也是标记接口。远程接口中的方法需要抛出RemoteException。
如下:
public interface Calculator extends Remote {
String calculate(String expr) throws RemoteException;
}
public class CalculatorServer implements Calculator {
public String calculate(String expr) throws RemoteException {// 实现远程接口
return expr;
}
public void start() throws RemoteException, AlreadyBoundException {
Calculator stub = (Calculator) UnicastRemoteObject.exportObject(
this, 0);// 创建一个能够被发布的对象
Registry registry = LocateRegistry.getRegistry();
registry.rebind("Calculator", stub);// 把自己注册并发布出去
}
}
在客户端直接访问就行:
public class CalculatorClient {
public void calculate(String expr) {
try {
Registry registry = LocateRegistry.getRegistry("localhost");// 服务器地址
Calculator calculator = (Calculator) registry
.lookup("Calculator");// 查找远程对象
String result = calculator.calculate(expr);// 直接调用
System.out.println(result);
} catch (Exception e) {
e.printStackTrace();
}
}
}
为了通过Java的序列化机制来进行传输,远程接口中的方法的参数和返回值,要么是Java的基本类型,要么是远程对象,要么是实现了 Serializable接口的Java类。当客户端通过RMI注册表找到一个远程接口的时候,所得到的其实是远程接口的一个动态代理对象。除了序列化之外,RMI还使用了动态类加载技术。当需要进行反序列化的时候,如果该对象的类定义在当前JVM中没有找到,RMI会尝试从远端下载所需的类文件定义。可以在RMI程序启动的时候,通过JVM参数java.rmi.server.codebase来指定动态下载Java类文件的URL。

java序列化和RMI相关推荐

  1. java基础(十)-----Java 序列化的高级认识

    将 Java 对象序列化为二进制文件的 Java 序列化技术是 Java 系列技术中一个较为重要的技术点,在大部分情况下,开发人员只需要了解被序列化的类需要实现 Serializable 接口,使用 ...

  2. 什么是java序列化_什么是Java序列化?为什么序列化?序列化有哪些方式?

    先普及一下,计算机中无法识别一个基本单元[字节]来表示,必须经过"翻译"才能让计算机理解人类的语言,这个翻译过程就是[编码],通常所说的字符转换为字节. ?有I/O的地方机就会涉及 ...

  3. Java序列化的作用和反序列化

    1.序列化是干什么的? 简单说就是为了保存在内存中的各种对象的状态(也就是实例变量,不是方法),并且可以把保存的对象状态再读出来.虽然你可以用你自己的各种各样的方法来保存object states,但 ...

  4. Java序列化技术与Protobuff

    前言: Java序列化是Java技术体系当中的一个重要议题,序列化的意义在于信息的交换和存储,通常会和io.持久化.rmi技术有关(eg:一些orm框架会要求持久化的对象类型实现Serializabl ...

  5. 深入理解JAVA序列化

    2019独角兽企业重金招聘Python工程师标准>>> 如果你只知道实现 Serializable 接口的对象,可以序列化为本地文件.那你最好再阅读该篇文章,文章对序列化进行了更深一 ...

  6. Java 序列化的高级认识

    这篇文章来自:http://www.ibm.com/developerworks/cn/java/j-lo-serial/index.html 引言 将 Java 对象序列化为二进制文件的 Java ...

  7. Java ---- 序列化

    Java对象的序列化 Java平台允许我们在内存中创建可复用的Java对象,但一般情况下,只有当JVM处于运行时,这些对象才可能存在,即,这些对象的生命周期不会比JVM的生命周期更长.但在现实应用中, ...

  8. java序列化的作用

    java序列化的作用 1.序列化是干什么的?        简单说就是为了保存在内存中的各种对象的状态(也就是实例变量,不是方法),并且可以把保存的对象状态再读出来.虽然你可以用你自己的各种各样的方法 ...

  9. Java中如何引用另一个类里的集合_【18期】Java序列化与反序列化三连问:是什么?为什么要?如何做?...

    Java序列化与反序列化是什么? Java序列化是指把Java对象转换为字节序列的过程,而Java反序列化是指把字节序列恢复为Java对象的过程: 序列化:对象序列化的最主要的用处就是在传递和保存对象 ...

最新文章

  1. 探讨UnsupportedOperationException的原因及解决方案
  2. 单元格编辑后级联汇总刷新
  3. WinForm界面开发之 启动界面
  4. 必会系列之 filter 和 interceptor 的区别
  5. 【递推DP】POJ1163The Triangle
  6. 词法分析(2)---NFA
  7. 剑指offer25-合并两个排序的链表
  8. JavaScript中通过点击单选框动态显示和隐藏组件
  9. 商品分析是什么?该怎么做(入门版)
  10. ctfshow 8神PNG隐写入门(土)赛 WP
  11. 周记20180413
  12. 爬虫练习案例:交通路况
  13. 谷歌浏览器反复提示PageOffice安装
  14. JAVA学习日志 关于调用方法、生成对象的例子。还是用数字卦程序修改
  15. 如何高效阅读一篇论文
  16. 前苏联IV-18荧光数码管时钟开发(ИВ-18)
  17. FLV科普2 FLV相关工具FlvParse
  18. python计算sin37_怎样计算 sin1°·sin2°·sin3°· … ·sin89°?
  19. 手机桌面便签app哪个比较好用
  20. JQuery用户注册表单验证

热门文章

  1. 应该知道关于Python的随机模型 以及使用范围例子洗牌 特别长 1米
  2. leetcode前缀树java_LeetCode 实现 Trie (前缀树)
  3. mysql行列转换例子_mysql行列转换示例
  4. python实现加密字符串_Python实现对字符串的加密解密方法示例
  5. 如何防止SSH会话断开连接
  6. Linux系统如何安装AutoFs挂载服务
  7. 如何用matlab读取npz文件,Python Numpy中数据的常用的保存与读取方法
  8. oracle rac应急_Support for Oracle RAC 框架资源组故障
  9. tensorflow算法实战:普通的数据训练和迁移学习之后的数据训练进行图像的识别(包括前端页面)
  10. BZOJ 1592. Making the Grade(思维,数据结构优化DP,以及三个拓展问题)[Usaco2008 Feb]【BZOJ计划】