满足下面四个条件中的一个的类就不应该被序列化:

   1.一个类与本地代码(native code)有紧密的关系,如java.util.zip.Deflater,这个类中很多都是native的。

  2.对象的内部状态依赖于java虚拟机或者运行状态,从而每次运行时状态都可能是不同的。例如Thread,InputStream等。

  3.串行化可能带来潜在的安全隐患,如java.lang.SecurityManager,java.security.MessageDigest等。

  4.一个类全是静态方法,没有内部状态,如java.lang.Math等。

 对象某些状态是瞬时的,无法保存。例如一个Thread对象或一个InputStream对象 ,对于这些字段,我们必须用transient关键字标明,避免将其序列化。

另外 ,串行化可能涉及将对象存放到磁盘上或在网络上发达数据,这时候就会产生安全问题。因为数据位于Java运行环境之外,不在Java安全机制的控制之中。对于这些需要保密的字段,不应保存在永久介质中 ,或者不应简单地不加处理地保存下来。不希望保存这些字段时,应该在这些字段前加上transient关键字。

或者还有一种办法,就是覆盖默认的Serializable接口的readObject(ObjectOutPutStream ous)方法和writeObject(ObjectInputStream ins)方法,在该方法中自定义序列化哪些字段,反序列化哪些字段。

  

  序列化还需要考虑的是版本问题,这个问题很经典了,如果一个类实现了序列化,那它必须承担起升版后如何保证接收端用老版本的类能成功反序列化的问题。jdk的解决方案是加入serialVersionUID字段,只要该字段值相同就认为是同一个对象。serialVersionUID可自己手动填 ,也可让IDE给你计算出一个。当该字段存在时,如果新版本的类传递到收端,收端根据该字段判断与老版本是同一对象时,它将”尽最大可能转换“,这意味着新版本的类里的新添加的方法,变量将被舍去。

当然你也可以自己定义版本问题的策略,比如你想要保证服务端和客户端部署的类版本始终保持一致,那你可以在新版本的类发布的时候,更改serialVersionUID字段值,这样在收端肯定会抛出serialVersionUID不一致异常,你可以捕获这个异常,然后提示客户端需要更新该类版本。

  序列化还需要注意以下的几点:

  •  序列化 ID 的问题
  •  静态变量序列化
  •  父类的序列化
  •  对敏感字段加密  

  序列化 ID 的问题,前面已经提到了序列化 ID的注意事项。这里要说的是需要在拷贝代码时注意,不能也将原类中的序列化 ID也拷贝到新的类中,这将会导致反序列化的失败。

  

  静态变量序列化,静态变量是不能被序列化的。

  父类的序列化,一个子类实现了 Serializable 接口,它的父类都没有实现 Serializable 接口,序列化该子类对象,然后反序列化后输出父类定义的某变量的数值,该变量数值与序列化时的数值不同。

  在父类没有实现 Serializable 接口时,虚拟机是不会序列化父对象的。而一个 Java 对象的构造必须先有父对象,才有子对象,反序列化也不例外。如果父类没有实现 Serializable 接口,则必须有无参的构造方法。

  对敏感字段加密,如密码字符串等,希望对该密码字段在序列化时,进行加密,而客户端如果拥有解密的密钥,只有在客户端进行反序列化时,才可以对密码进行读取,这样可以一定程度保证序列化对象的数据安全。

  在序列化过程中,虚拟机会试图调用对象类里的 writeObject 和 readObject 方法,进行用户自定义的序列化和反序列化。 

private static final long serialVersionUID = 1L;

    private String password = "pass";

    public String getPassword() {
return password;
} public void setPassword(String password) {
this.password = password;
} private void writeObject(ObjectOutputStream out) {
try {
PutField putFields = out.putFields();
System.out.println("原密码:" + password);
password = "encryption";//模拟加密
putFields.put("password", password);
System.out.println("加密后的密码" + password);
out.writeFields();
} catch (IOException e) {
e.printStackTrace();
}
} private void readObject(ObjectInputStream in) {
try {
GetField readFields = in.readFields();
Object object = readFields.get("password", "");
System.out.println("要解密的字符串:" + object.toString());
password = "pass";//模拟解密,需要获得本地的密钥
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
} } public static void main(String[] args) {
try {
ObjectOutputStream out = new ObjectOutputStream(
new FileOutputStream("result.obj"));
out.writeObject(new Test());
out.close(); ObjectInputStream oin = new ObjectInputStream(new FileInputStream(
"result.obj"));
Test t = (Test) oin.readObject();
System.out.println("解密后的字符串:" + t.getPassword());
oin.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}

  RMI 技术是完全基于 Java 序列化技术的,服务器端接口调用所需要的参数对象来至于客户端,它们通过网络相互传输。这就涉及 RMI 的安全传输的问题。一些敏感的字段,如用户名密码(用户登录时需要对密码进行传输),我们希望对其进行加密,这时,就可以采用本节介绍的方法在客户端对密码进行加密,服务器端进行解密,确保数据传输的安全性。

  序列化存储规则,Java 序列化机制为了节省磁盘空间,具有特定的存储规则,当写入文件的为同一对象时,并不会再将对象的内容进行存储,而只是再次存储一份引用,上面增加的 5 字节的存储空间就是新增引用和一些控制信息的空间。反序列化时,恢复引用关系,使得例子中的 t1 和 t2 指向唯一的对象,二者相等,输出 true。该存储规则极大的节省了存储空间。

ObjectOutputStream out = new ObjectOutputStream(
new FileOutputStream("result.obj"));
Test test = new Test();
//试图将对象两次写入文件
out.writeObject(test);
out.flush();
System.out.println(new File("result.obj").length());
out.writeObject(test);
out.close();
System.out.println(new File("result.obj").length()); ObjectInputStream oin = new ObjectInputStream(new FileInputStream(
"result.obj"));
//从文件依次读出两个文件
Test t1 = (Test) oin.readObject();
Test t2 = (Test) oin.readObject();
oin.close(); //判断两个引用是否指向同一个对象
System.out.println(t1 == t2);

  输出结果为:31 36 true

序列化与transient的更多相关文章

  1. Java序列化(含transient)

    什么是序列化? 我们创建的对象只有在Java虚拟机保持运行时,才会存在于内存中.如果想要超出Java虚拟机的生命周期,就可以将对象序列化,将对象状态转换为字节序列,写入文件(或socket传输),后面 ...

  2. Java序列化之transient和serialVersionUID的使用

    package FileDemo; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IO ...

  3. 原!上线遇到的问题, java序列化关键字transient 修饰的属性变成null了

    1.问题描述: 某个功能点,user对象 放入session,后再另外地方取出,结果某个字段没有了.再本地和测试环境都是ok的,但是线上环境就是不行. 后来看到这个user对象的那个属性是加了tran ...

  4. 对象序列化中transient关键字的用途

  5. 序列化、反序列化和transient关键字的作用

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

  6. Effective java笔记(十),序列化

    将一个对象编码成字节流称作将该对象「序列化」.相反,从字节流编码中重新构建对象被称作「反序列化」.一旦对象被「序列化」后,它的编码就可以从一台虚拟机传递到另一台虚拟机,或被存储到磁盘上,供以后「反序列 ...

  7. Java中的序列化Serialable高级详解

    来自[http://blog.csdn.net/jiangwei0910410003/article/details/18989711] 引言 将 Java 对象序列化为二进制文件的 Java 序列化 ...

  8. 类的序列化和反序列化(ObjectOutputStream和ObjectInputStream)

    1.需要序列化的类 import java.io.Serializable; /** * 必须继承 Serializable 接口才能实现序列化 */ public class Employee im ...

  9. 黑马程序员_Java基础:序列化(Serializable)与反序列化

    ------- android培训.java培训.期待与您交流! ---------- 在学习IO中的ObjectOutputStream和ObjectInputStream时,会涉及到序列化和反序列 ...

随机推荐

  1. 水dp第二天(背包有关)

    水dp第二天(背包有关) 标签: dp poj_3624 题意:裸的01背包 注意:这种题要注意两个问题,一个是要看清楚数组要开的范围大小,然后考虑需要空间优化吗,还有事用int还是long long ...

  2. 炫酷线条动画--svg

    我们经常可以在一些页面看到看起来很酷的线条动画,有些可以用css实现,有些css就无能为力了,今天来研究另一种实现方式,svg 如果对svg是什么还不了解的话,可以先去看看svg的基础教程: 一般对于 ...

  3. -------- ROOTKIT 核心技术——系统服务调度表挂钩调试(PART III) --------

    ---------------------------------------------------------------------------------------- 本篇开始进行真枪实弹的 ...

  4. Linuxc - 标准输入流、标准输出流、标准错误流

    输入流stdin默认是键盘,输出流stdout默认是显示器,错误流stderr #include <stdio.h> int main() { printf("请输入选择的数字: ...

  5. python生产随机数案例

    法1: list =list(string.lowercase + string.uppercase) + [str(i) for i in range(10)]FH=('!','@','#','$' ...

  6. java8大基本数据类型

    基本类型 字节数 位数 最大值 最小值 byte 1byte 8bit 2^7 - 1 -2^7 short 2byte 16bit 2^15 - 1 -2^15 int 4byte 32bit 2^ ...

  7. junit测试延伸--方法的重复测试

    在实际编码测试中,我们有的时候需要对一个方法进行多次测试,那么怎么办呢?这个问题和测试套件解决的方案一样,我们总不能不停的去右键run as,那怎么办呢?还好伟大的junit帮我们想到了. OK,现在 ...

  8. Servlet--HttpServletResponse的2个操作流的方法

    前面已经说过无数多次了,我们的项目都是基于HTTP协议的一次请求,一次响应.实际编码中,我们在处理完逻辑后一般是跳转到一个页面上,或者用输出流返回json字符串.其实跳转到一个页面往往也就是JSP,J ...

  9. 2017 .NET 開發者須知

    筆記-Scott Hanselman 的 2017 .NET 開發者須知 转载http://blog.darkthread.net/post-2017-01-16-dotnet-dev-should- ...

  10. Oracle 视图 (待更新, 缓存)

    参考: 视图.索引.存储过程优缺点: http://www.cnblogs.com/SanMaoSpace/p/3147059.html oracle视图总结(转):http://tianwei013 ...