客户端访问了某个能开启会话功能的资源, web服务器就会创建一个与该客户端对应的HttpSession对象,每个HttpSession对象都要站用一定的内存空间。如果在某一时间段内访问站点的用户很多,web服务器内存中就会积累大量的HttpSession对象,消耗大量的服务器内存,即使用户已经离开或者关闭了浏览器,web服务器仍要保留与之对应的HttpSession对象,在他们超时之前,一直占用web服务器内存资源。
web服务器通常将那些暂时不活动但未超时的HttpSession对象转移到文件系统或数据库中保存,服务器要使用他们时再将他们从文件系统或数据库中装载入内存,这种技术称为Session的持久化。
将HttpSession对象保存到文件系统或数据库中,需要采用序列化的方式将HttpSession对象中的每个属性对象保存到文件系统或数据库中;将HttpSession对象从文件系统或数据库中装载如内存时,需要采用反序列化的方式,恢复HttpSession对象中的每个属性对象。所以存储在HttpSession对象中的每个属性对象必须实现Serializable接口。
序列化和反序列化的概念
序列化:将Java对象转换为字节流(可以存储或者传输)的过程称为对象的序列化。在序列化期间,对象将其当前状态写入到临时或者持久性存储区。
反序列化:将字节流恢复成Java对象的过程称为对象的反序列化。
序列化的实现:类通过实现 java.io.Serializable 接口以启用其序列化功能。未实现此接口的类将无法使其任何状态序列化或反序列化。实现Serializable接口是为了告诉jvm这个类的对象可以被序列化。
注意事项:
1.某个类可序列化,则其继承该类的子类也可以被序列化。
2.声明为static的成员变量或者transient修饰的属性,不能被系列化。static变量是类级别的属性,transient修饰的是临时变量。(下面会进行测试)
什么情况化需要系列化
1.将对象存储在硬盘上。
2.将对象通过网络传输。
3.通过RMI远程调用等方式传输对象的时候
serialVersionUID 的作用
serialVersionUID 用来表明类的不同版本间的兼容性
Java的序列化机制是通过在运行时判断类的serialVersionUID来验证版本一致性的。在进行反序列化时,JVM会把传来的字节流的serialVersionUID与本地相应实体(类)的serialVersionUID进行比较,如果相同就认为是一致的,可以进行反序列化,否则就会出现序列化版本不一致的异常。
当实现java.io.Serializable接口的实体(类)没有显式地定义一个名为serialVersionUID,类型为long的变量时,Java序列化机制会根据编译的class自动生成一个serialVersionUID作序列化版本比较用,这种情况下,只有同一次编译生成的class才会生成相同的serialVersionUID。不过,强烈建议 所有可序列化类都显式声明 serialVersionUID 值,原因是计算默认的 serialVersionUID 对类的详细信息具有较高的敏感性,根据编译器实现的不同可能千差万别,这样在反序列化过程中可能会导致意外的 InvalidClassException。
实现序列化
序列化,就是为了在不同时间或不同平台的JVM之间共享实例对象
序列化对象,代码如下:
package com.lf;
import java.io.Serializable;
public class Demo implements Serializable {
// private static final long serialVersionUID = 1L;
private static String NUM = "11";
private String name;
transient private String age;
public static String getNUM() {
return NUM;
}
public static void setNUM(String NUM) {
Demo.NUM = NUM;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getAge() {
return age;
}
public void setAge(String car) {
this.age = car;
}
@Override
public String toString() {
return "Demo{" +
"name='" + name + '\'' +
", age='" + age + '\'' +
", NUM='" + NUM + '\'' +
'}';
}
}
测试代码如下:
package com.lf;
import java.io.*;
public class Test {
/**
* 序列化
* @throws IOException
*/
private static void serializableDemo() throws IOException{
Demo demo = new Demo();
demo.setName("alien");
demo.setAge("15");
//ObjectOutputStream 对象输出流,对demo对象进行序列化,存储到demo.txt中
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(new File("C:\\Users\\Administrator\\Desktop\\demo.txt")));
oos.writeObject(demo);
System.out.println("demo序列化成功");
oos.close();
}
/**
* 反序列化
* @return
* @throws Exception
*/
private static Demo deserializableDemo() throws Exception{
ObjectInputStream ois = new ObjectInputStream(new FileInputStream(new File("C:\\Users\\Administrator\\Desktop\\demo.txt")));
Demo person = (Demo) ois.readObject();
System.out.println("demo反序列化成功");
return person;
}
public static void main(String[] args) throws Exception{
//序列化
serializableDemo();
//反序列化
Demo demo = deserializableDemo();
//打印,验证
System.out.println(demo.toString());
}
}
运行结果,生成demo.txt文件:
从运行的结果上看:
1.成功实现了对象的序列化和反序列化。age属性的值为null,说明了transient修改的属性,是不会被序列化的。
2.静态变量NUM这个得另外测。
验证静态属性能否序列化
1.首先先把Java对象序列化到文件。这个对象中的静态(static)变量的属性值为11.运行结果如下,序列化成功:
2.接下来再把Java对象中的静态(static)变量的属性值更改为22,然后对刚才的文件进行反序列化。
运行结果如下:
结果分析:刚才序列化的静态变量属性值是11,就是说反序列化出来是11,而结果是22,所以得出结论,静态static的属性,不能序列化。