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

   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. HDU 1003 Max Sum【动态规划求最大子序列和详解 】

    Max Sum Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Total Sub ...

  2. [51nod1440]迈克打电话

    有n只熊,从1到n进行编号. 第i只熊的电话号码是si.每只熊会给那些电话号码是他的子串的熊打电话(可能会给自己打). call(i, j) 表示第i只熊给第j只熊打电话的次数,也就是第j个串在第i个 ...

  3. 从XMLHttpRequest请求响应里getResponseHeader(header)报错:Refused to get unsafe header "**" 问题解决

    问题产生原因: 原因1:W3C的 xhr 标准中做了限制,规定客户端无法获取 response 中的 Set-Cookie.Set-Cookie2这2个字段,无论是同域还是跨域请求: 原因2:W3C ...

  4. SSL证书安装指引

    https://cloud.tencent.com/document/product/400/4143 下载得到的 www.domain.com.zip 文件,解压获得3个文件夹,分别是Apache. ...

  5. vue学习笔记(二)——简单的介绍以及安装

    学习编程需要的是 API+不断地练习^_^ Vue官网:https://cn.vuejs.org/ 菜鸟教程:http://www.runoob.com/vue2/vue-tutorial.html ...

  6. 浅析RPC概念框架

    本文原封不动的来至于csdn MindWind,原文请见 RPC:RPC 的全称是 Remote Procedure Call 是一种进程间通信方式.它允许程序调用另一个地址空间(通常是共享网络的另一 ...

  7. Jasper之table报表

    这段时间用Jasper画报表,讲真的Jasper IDE真的很难用,网上找很久都没找到用table画的配置方法,以下是直接操作源码画table的方法,不用IDE一样可以做出来(不过样式还是得借助IDE ...

  8. assembly 基础

    body, table{font-family: 微软雅黑; font-size: 13.5pt} table{border-collapse: collapse; border: solid gra ...

  9. JavaScript ECMAScript版本介绍

    1. 介绍 1.1 什么是ECMAScript ECMAScript,简称ES,是由Ecma国际(前身为欧洲计算机制造商协会,英文名称是European Computer Manufacturers ...

  10. Springboot中使用AOP统一处理Web请求日志

    title: Springboot中使用AOP统一处理Web请求日志 date: 2017-04-26 16:30:48 tags: ['Spring Boot','AOP'] categories: ...