java中序列化与反序列化
1. 序列化与反序列的定义:
1.序列化:把java对象转化成字节序列的过程
2.反序列:把字节序列恢复为原java对象的过程
2. 为什么需要序列化与反序列化
1.当两个进程之间通信时,可以传递各种类型的数据,如:文本,图片,音频,视频,而这些数据都会以二进制形式在网络上传送,那么在两个java进程进行通信时,能否实现进程间对象的传递呢。答案是肯定,如何做到呢,这就需要序列化与反序列化。
2.一方面,发送方需要把这个java对象转化成字节序列,然后在网络上传送,另一方面,接收方需要把字节序列恢复成原来的java对象。
3. 序列化的意义
1.一是,可以实现数据的持久化,通过序列化可以把数据持久的保存到磁盘上(通常放在文件中)
2.二是,利用序列化可以实现远程通信,即在网络上传送字节序列
4. 序列化实现方式
1)jdk中的API
ObjectOutputStream 输出流
writeObject(Object obj)对指定的参数对象进行序列化,把得到的字节序列写到一个目标输出流中。
ObjectInputStream 输入流
readObject() 从输入流中读取字节序列,再把它们反序列成一个对象返回
2)实现序列化的要求
只有实现了Serializable或Externalizable接口的类的对象才能被序列化,否则抛出异常
3)实现序列化与反序列化的方法
假定一个Student类,它的对象需要序列化,可以有如下三种方法:
方法一:若Student类仅仅实现了Serializable接口,则可以按照以下方式进行序列化和反序列化
ObjectOutputStream采用默认的序列化方式,对Student对象的非transient的实例变量进行序列化。
ObjcetInputStream采用默认的反序列化方式,对对Student对象的非transient的实例变量进行反序列化。
方法二:若Student类仅仅实现了Serializable接口,并且还定义了readObject(ObjectInputStream in)和writeObject(ObjectOutputSteam out),则采用以下方式进行序列化与反序列化。
ObjectOutputStream调用Student对象的writeObject(ObjectOutputStream out)的方法进行序列化。
ObjectInputStream会调用Student对象的readObject(ObjectInputStream in)的方法进行反序列化。
(定制的序列化可以序列被static以及transient修饰的变量)
方法三:若Student类实现了Externalnalizable接口,且Student类必须实现readExternal(ObjectInput in)和writeExternal(ObjectOutput out)方法,则按照以下方式进行序列化与反序列化。
(第三种方法不管是否被transient和static修饰,都会被序列化)
ObjectOutputStream调用Student对象的writeExternal(ObjectOutput out))的方法进行序列化。
ObjectInputStream会调用Student对象的readExternal(ObjectInput in)的方法进行反序列化。
5. 序列化注意的事项
1.哪些可以被序列化:对象的类名、Field(包括基本类型、数组、对其他对象的引用)
2.哪些不可以被序列化:static修饰的变量、transient修饰的变量、方法
3.static修饰的变量不能被序列化的原因
同一个JVM内部只会存在静态变量的一个实例,当然他们是一样的了。也就是说,静态变量并没有被序列化,而只是存在于JVM内部,当反序列化的时候,JVM用的还是这一个实例,难怪他们会是一样的了!
6. transient注意的事项
1.transient只能修饰变量,不能修饰方法和类,本地变量不能被transient关键字修饰
2.一旦被transient修饰,该变量就不是持久化的一部分,该变量内容在序列化后将无法获得,也可以认为,在将持久化的对象反序列化后,被transient修饰的变量将按照普通的类成员变量一样被初始化
7. 代码
方法一:
public class Person implements Serializable {
private String name;
private int age;
private transient Date date = new Date();
private static int staticValue = 11;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public Date getDate() {
return date;
}
public void setDate(Date date) {
this.date = date;
}
public static int getStaticValue() {
return staticValue;
}
public static void setStaticValue(int staticValue) {
Person.staticValue = staticValue;
}
@Override
public String toString() {
return String.format("My name is %s, and I'm %d years old. %tc,%d",
name, age,date,staticValue);
}
}
public class SerializableDemo {
/**
* 1.序列化与反序列的定义:
* 序列化:把java对象转化成字节序列的过程
* 反序列:把字节序列恢复为原java对象的过程
* 2.为什么需要序列化与反序列化
* 当两个进程之间通信时,可以传递各种类型的数据,如:文本,图片,音频,视频,而这些数据都会以二进制形式在网络上传送,那么在两个java进程进行通信时,能否实现进程间对象的传递呢。答案是肯定,如何做到呢,这就需要序列化与反序列化。
* 一方面,发送方需要把这个java对象转化成字节序列,然后在网络上传送,另一方面,接收方需要把字节序列恢复成原来的java对象。
* 3.序列化的意义
* 一是,可以实现数据的持久化,通过序列化可以把数据持久的保存到磁盘上(通常放在文件中)
* 二是,利用序列化可以实现远程通信,即在网络上传送字节序列
* 4.序列化实现方式
* 1)jdk中的API
* ObjectOutputStream 输出流
* writeObject(Object obj)对指定的参数对象进行序列化,把得到的字节序列写到一个目标输出流中。
* ObjectInputStream 输入流
* readObject() 从输入流中读取字节序列,再把它们反序列成一个对象返回
* 2)实现序列化的要求
* 只有实现了Serializable或Externalizable接口的类的对象才能被序列化,否则抛出异常
* 3)实现序列化与反序列化的方法
* 假定一个Student类,它的对象需要序列化,可以有如下三种方法:
* 方法一:若Student类仅仅实现了Serializable接口,则可以按照以下方式进行序列化和反序列化
* ObjectOutputStream采用默认的序列化方式,对Student对象的非transient的实例变量进行序列化。
* ObjcetInputStream采用默认的反序列化方式,对对Student对象的非transient的实例变量进行反序列化。
* 方法二:若Student类仅仅实现了Serializable接口,并且还定义了readObject(ObjectInputStream in)和writeObject(ObjectOutputSteam out),则采用以下方式进行序列化与反序列化。
* ObjectOutputStream调用Student对象的writeObject(ObjectOutputStream out)的方法进行序列化。
* ObjectInputStream会调用Student对象的readObject(ObjectInputStream in)的方法进行反序列化。
* (定制的序列化可以序列被static以及transient修饰的变量)
* 方法三:若Student类实现了Externalnalizable接口,且Student类必须实现readExternal(ObjectInput in)和writeExternal(ObjectOutput out)方法,则按照以下方式进行序列化与反序列化。
* (第三种方法不管是否被transient和static修饰,都会被序列化)
* ObjectOutputStream调用Student对象的writeExternal(ObjectOutput out))的方法进行序列化。
* ObjectInputStream会调用Student对象的readExternal(ObjectInput in)的方法进行反序列化。
* 5.序列化注意的事项
* 哪些可以被序列化:对象的类名、Field(包括基本类型、数组、对其他对象的引用)
* 哪些不可以被序列化:static修饰的变量、transient修饰的变量、方法
* static修饰的变量不能被序列化的原因
* 同一个JVM内部只会存在静态变量的一个实例,当然他们是一样的了。也就是说,静态变量并没有被序列化,而只是存在于JVM内部,当反序列化的时候,JVM用的还是这一个实例,难怪他们会是一样的了!
* 6.transient注意的事项
* transient只能修饰变量,不能修饰方法和类,本地变量不能被transient关键字修饰
* 一旦被transient修饰,该变量就不是持久化的一部分,该变量内容在序列化后将无法获得,也可以认为,在将持久化的对象反序列化后,被transient修饰的变量将按照普通的类成员变量一样被初始化
*/
public static void main(String[] args) throws Exception {
Person person = new Person("peron",10);
ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream(
new File("0xjh000")));
out.writeObject(person);
person.setAge(111);
person.setStaticValue(3);
ObjectInputStream in = new ObjectInputStream(new FileInputStream(
new File("0xjh000")));
Person person1 = (Person) in.readObject();
System.out.println(person1);
}
}
方法二:
public class Person1 implements Serializable{
private static String name;
private transient int age;
public Person1() {
}
public Person1(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
private void writeObject(java.io.ObjectOutputStream out) throws IOException {
out.writeObject(new StringBuffer(name).reverse());
out.writeInt(age);
out.close();
}
private void readObject(java.io.ObjectInputStream in) throws Exception{
this.name = ((StringBuffer)in.readObject()).reverse().toString();
this.age = in.readInt();
in.close();
}
public static void main(String[] args) throws Exception {
Person1 pre = new Person1("WSDFG",10);
pre.writeObject(new ObjectOutputStream(new FileOutputStream(new File("s"))));
Person1.name="weffg";
Person1 p = new Person1();
p.readObject(new ObjectInputStream(new FileInputStream(new File("s"))));
System.out.println(p.age+" "+p.name);
}
}
方法三:
public class ExternalizableTest implements Externalizable{
private static String content = "哈哈~我将会被序列化,不管我是是否被transient和static关键字修饰";
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
@Override
public void writeExternal(ObjectOutput out) throws IOException {
out.writeObject(content);
}
@Override
public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
content = (String) in.readObject();
}
public static void main(String[] args) throws Exception {
ExternalizableTest et = new ExternalizableTest();
ObjectOutput out = new ObjectOutputStream(new FileOutputStream(
new File("ext0000")));
out.writeObject(et);
ExternalizableTest.content="ss";
ObjectInput in = new ObjectInputStream(new FileInputStream(new File(
"ext0000")));
ExternalizableTest et1 = (ExternalizableTest) in.readObject();
System.out.println(et1.content);
out.close();
in.close();
}
}