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

   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. happymall 第十一章订单表 数据表设计

    为订单号生成唯一索引,用用户id和订单号生成组合索引提高查询效率.

  2. html日历(1)

    <html> <head> <link rel="stylesheet" type="text/css" href="S ...

  3. HDU 5912 Fraction(模拟——分子式化简求解)

    题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=5912 Problem Description Mr. Frog recently studied h ...

  4. Web前端性能优化——如何提高页面加载速度

    前言:  在同样的网络环境下,两个同样能满足你的需求的网站,一个"Duang"的一下就加载出来了,一个纠结了半天才出来,你会选择哪个?研究表明:用户最满意的打开网页时间是2-5秒, ...

  5. 阿里云邮箱POP3、SMTP设置教程

    3G免费网www.3gmfw.cn免费为你分享阿里云邮箱POP3.SMTP设置教程,阿里云邮箱 阿里云邮箱POP3设置 阿里云邮箱SMTP设置的相关资源如下: 什么是POP3.SMTP? 阿里云邮箱已 ...

  6. 邓_html_选项卡

    ================================================= ================[  选项卡  ]================= ======= ...

  7. 数据库复习总结(16)-case关键字(数据透视)

    case语法: 练习1:将性别的0.1显示为男.女 select * from StudentInfo --case:对结果集中的列进行判断 --例1:显示学生信息,性别以"男女" ...

  8. CUDA与OpenGL互操作

    当处理较大数据量的时候,往往会用GPU进行运算,比如OpenGL或者CUDA.在实际的操作中,往往CUDA实现并行计算会比OpenGL更加方便,而OpenGL在进行后期渲染更具有优势.由于CUDA中的 ...

  9. Python系列之入门篇——MYSQL

    Python系列之入门篇--MYSQL 简介 python提供了两种mysql api, 一是MySQL-python(不支持python3),二是PyMYSQL(支持python2和python3) ...

  10. CCF系列之I’m stuck!(201312-5)

    试题名称: I’m stuck! 时间限制: 1.0s 内存限制: 256.0MB 问题描述: 问题描述 给定一个R行C列的地图,地图的每一个方格可能是'#', '+', '-', '|', '.', ...