工作有几个年头了,也想写些东西。把我所了解的java序列化写出来,知识共享。
java序列化:
当2个java进程进行远程通信的时候,需要发送方把对象转换为字节序列(对象的序列化),然后在网络上传输。
接收方需要把接受到的字节序列恢复成java对象(对象的反序列化)后,使用该对象。
实现:
要想实现java的序列化,需要实现(implements)java.io.Serializable接口或者java.io.Externalizable接口
实现序列化。
简单的例子,创建Customer对象储存本地customer.dat文件中。然后把序列化的字节恢复成Customer对象。
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
public class Customer implements java.io.Serializable {
/**
* serialVersionUID.
*/
private static final long serialVersionUID = 4186775250920519367L;
/**
* customer'name property.
*/
private String name;
/**
* customer' address property.
*/
private String address;
/**
* construct a new Customer instance with name and address argument.
* @param name - customer's name.
* @param address - customer'address.
*/
public Customer(String name,String address) {
this.name = name;
this.address = address;
}
/**
* get customer's name.
* @return customer's name.
*/
public String getName() {
return name;
}
/**
* set customer's name property.
* @param name - name.
*/
public void setName(String name) {
this.name = name;
}
/**
* get customer's address.
* @return - address.
*/
public String getAddress() {
return address;
}
/**
* set customer's address.
* @param address -address.
*/
public void setAddress(String address) {
this.address = address;
}
/**
*
*/
public boolean equals(Object obj) {
if(obj == this) {
return true;
}
if(!(obj instanceof Customer)) {
return false;
}
Customer c = (Customer) obj;
return (name.equals(c.getName()) && address.equals(c.getAddress()));
}
public int hashCode() {
return name.hashCode() + address.hashCode();
}
public String toString() {
return "[" + name + "," + address + "]";
}
private void readObject(ObjectInputStream objectinputstream) throws ClassNotFoundException, IOException {
objectinputstream.defaultReadObject();
}
private void writeObject(ObjectOutputStream objectOutputStream) throws IOException {
objectOutputStream.defaultWriteObject();
}
public static void main(String[] args) {
Customer c = new Customer("zc","liaoning.dl");
//Serialize
System.out.println("before serialize:" + c);
ObjectOutputStream oos = null;
try {
oos = new ObjectOutputStream(new FileOutputStream("c:\\customer.dat"));
oos.writeObject(c);
} catch (FileNotFoundException e) {
//ignore
} catch (IOException e) {
//ignore
} finally {
try {
if(oos != null) {
oos.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
//deserialize
ObjectInputStream ois = null;
Customer c2 = null;
try {
ois = new ObjectInputStream(new FileInputStream("c:\\customer.dat"));
c2 = (Customer) ois.readObject();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
} finally {
try {
if(ois != null) {
ois.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
System.out.println("deserialize:" + c2);
System.out.println("compare result:" + c.equals(c2));
}
}
执行结果:
before serialize:[zc,liaoning.dl]
deserialize:[zc,liaoning.dl]
compare result:true
上面就是简单的序列化例子。
从上面例子可以看出序列化前后对象比较是equal,真正意义上2个对象,只是内容相同而已。如何能让序列化后的对象绝对相等(==比较)?
也就是说单例如何序列化后的对象是一个?(用java中反射获得的单例对象,其实也是一个新对象)
下面是一个最简单的单例模式:
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
public class Singleton implements java.io.Serializable {
private static Singleton instance = new Singleton();
private Singleton() {}
public static Singleton getInstance() {
return instance;
}
public static void main(String[] args) {
Singleton singleton = Singleton.getInstance();
ObjectOutputStream oos = null;
try {
oos = new ObjectOutputStream(new FileOutputStream("c:\\singleton.dat"));
oos.writeObject(singleton);
} catch (FileNotFoundException e) {
//ignore
} catch (IOException e) {
//ignore
} finally {
try {
if(oos != null) {
oos.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
//deserialize
ObjectInputStream ois = null;
Singleton singleton2 = null;
try {
ois = new ObjectInputStream(new FileInputStream("c:\\singleton.dat"));
singleton2 = (Singleton) ois.readObject();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
} finally {
try {
if(ois != null) {
ois.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
System.out.println(singleton == singleton2);
}
}
执行结果:
false
如果在单例中实现如下方法:
private Object readResolve() {
return instance;
}
执行结果:
true
readResolve方法把序列化后的对象覆盖,返回readResolve方法值。
在实现序列化的过程中,有许多需要注意的地方。
在网络的传输的过程中,有可能把传输的字节码修改。这对于类中对某一个属性有限制(比如年龄<120),修改成非法的字节码。
详细的内容请查看 effective java的第10章序列化中的内容。