您的位置:首页 > 其它

对象的序列化

2015-10-15 11:36 351 查看
对象的序列化

何为序列化和反序列化?

序列化机制允许将实现序列化的java对象转换成字节序列,这些字节序列可以保存在磁盘上,或者通过网络的传输,以备以后重新恢复成原来的对象。序列化机制使得对象可以脱离程序的运行独立存在。

对象的序列化指将一个java对象写入IO流中,与此对应的是,对象的反序列化则指从IO流中恢复该java对象。

如何将对象设置为可序列化的?

将类实现Serializable接口。这只是一个标记接口,没有任何的方法。

对象的序列化的用途?

所有可能在网络上传输的对象都应该是可序列化的,否则程序将会出现异常。比如RMI(远程方法调用,是java ee的基础)过程的参数和返回值;所有因为保存到磁盘里的对象的类都必须可序列化,

比如Web应用中需要保存到HttpSession或者ServletContext属性的java对象。

因为序列化是RMI过程的参数和返回值都必须实现的机制,而RMI又是java EE 技术的基础---------所有的分布式应用常常需要跨平台,跨网络,所以要求所有传递的参数,返回值必须实现序列化,

因此:序列化机制是java EE平台的基础。通常建议:程序创建的每一个JavaBean类都实现Seralizable.

对象序列化与反序列化的应用实例:

1.将对象写入磁盘,然后读出。

1.将对象所属的类实现Serialize接口:

public class Student implements Serializable{

private String name;

private int age;

public Student(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;

}

@Override

public String toString() {

return "Student [name=" + name + ", age=" + age + "]";

}

}

public class Test {

public static void main(String[] args) {

Student st=new Student("徐才厚", 17);

//创建File对象

File file=new File("D:\\3.txt");

try {

//创建一个ObjectOutPutStream输出流

ObjectOutputStream oos=new ObjectOutputStream

(new FileOutputStream(file));

//序列化teacher对象

oos.writeObject(st);

//创建一个ObjectInputStream输入流

ObjectInputStream ois=new ObjectInputStream

(new FileInputStream(file));

Student stu=(Student) ois.readObject();

System.out.println(stu);

} catch (Exception e) {

// TODO Auto-generated catch block

e.printStackTrace();

}

}

}

2.将对象在网络上传输,在网络上传输时,在服务的另一端,反序列化读取的仅仅是java对象的数据,而不是Java类,因此反序列化恢复java对象时,必须提供Java对象所属类的class文件,否则将会引发ClassNotFoundException异常。

但是在客户端和服务器端都必须有Person类的class文件。

客户端:

public class Person implements Serializable{

private String name;

private int age;

public Person(String name, int age) {

super();

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;

}

@Override

public String toString() {

return "Person [name=" + name + ", age=" + age + "]";

}

}

public class Client {

public static void main(String[] args) {

try {

Socket socket=new Socket("localhost", 9999);

OutputStream os=socket.getOutputStream();

ObjectOutputStream oos=new ObjectOutputStream(os);

Person per=new Person("徐才厚", 19);

oos.writeObject(per);

//加flush与不加flush影响不大,但是一般都加上,确保数据全部都能在通道里传输。

oos.flush();

} catch (Exception e) {

// TODO Auto-generated catch block

e.printStackTrace();

}

}

}

服务器端:

public class Person implements Serializable{

private String name;

private int age;

public Person(String name, int age) {

super();

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;

}

@Override

public String toString() {

return "Person [name=" + name + ", age=" + age + "]";

}

}

public class server {

public static void main(String[] args) {

try {

ServerSocket ss=new ServerSocket(9999);

Socket socket=ss.accept();

InputStream is=socket.getInputStream();

ObjectInputStream ois=new ObjectInputStream(is);

Object obj=ois.readObject();

System.out.println(obj);

} catch (Exception e) {

// TODO Auto-generated catch block

e.printStackTrace();

}

}

}

2.自定义序列化

实现一:

如果我们不想序列化对象中的某个字段,我们一般在对象所属的类中的字段前加上transient关键字。这样在序列化对象时,此字段的值不会被序列化。就像上一个Person类,如果age这个字段

被transient修饰,则,打印对象的时候,这时候age为默认值为0.

实现二:

我们可以重写Person对象的

private void writeObject(java.io.ObjectOutputStream out) throws IOException {

} 和

private void readObject(java.io.ObjectInputStream io) throws IOException,ClassNotFoundexception{

}

writeObject()方法负责写入特定类的实例状态,以便相应的readObject()方法可以恢复它,通过重写此方法,我们可以完全获得对序列化

机制的控制,可以自主决定哪些Fileld需要序列化,需要怎样的序列化。这样同时保证了网络传输的安全性,因为在传输时,进行了加密。

同时readObject()方法负责从流中读取并恢复对象Field,通过重写该方法,我们可以完全获得对反序列化机制的控制,可以自主决定需要反序列化

哪些字段,以及如何进行反序列化。如果writeObject()方法中对java对象进行了一些处理,则应该在readObject()方中,对其Field字段

进行相应的处理,以便正确的恢复该对象。

代码示例:其他的代码,与上面的代码一样。

public class Student implements Serializable{

private String name;

private int age;

public Student(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;

}

/***

* 功能:对于自定义的序列化,序列化和反序列化Person实例没有任何的

* 区别,区别在于序列化的对象流,即使有Cracker截获到Person对象流

* ,看到的name也是加密后的name,这样就提高了序列化的安全性,这样

* 在网络流中是安全的。同时在序列化时,你可以自行的定义哪些字段可以序列化

* 哪些字段不可序列化。这个这样的话可以进行加密。网络传输更安全。重写

* writeObject()方法和readObject()方法。

* *******/

private void writeObject(java.io.ObjectOutputStream out){

try {

//将name Field值反转后写入二进制流

out.writeObject(new StringBuffer(name).reverse());

//out.writeInt(age);

} catch (Exception e) {

// TODO Auto-generated catch block

e.printStackTrace();

}

}

private void readObject(java.io.ObjectInputStream in){

try {

//将读取的字符串反转后赋给name field

this.name=((StringBuffer)in.readObject()).reverse().toString();

//this.age=in.readInt();

} catch (IOException e) {

// TODO Auto-generated catch block

e.printStackTrace();

} catch (ClassNotFoundException e) {

// TODO Auto-generated catch block

e.printStackTrace();

}

}

@Override

public String toString() {

return "Student [name=" + name + ", age=" + age + "]";

}

}

实现三:

Java的序列化机制保证在序列化某个对象之前,先调用该对象的writeReplace()方法,如果该方法返回另一个对象

,则系统转化为序列化另一个Java对象。

/**

*功能的描述:

*java的序列化机制保证在序列化某个对象之前,先调用该该对象的

*writeReplace()方法,如果该方法返回另一个java对象,则系统

*转化为序列化另一个对象,此程序表面上是序列化Person对象,实际

*上是序列化ArrayList对象。

*

* ***/

public class Teacher implements java.io.Serializable {

private String name;

private int age;

private char sex;

public Teacher(String name, int age) {

super();

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 Object writeReplace() throws ObjectStreamException

{

ArrayList<Object>list=new ArrayList<Object>();

list.add(name);

list.add(age);

return list;

}

}

测试代码:

public class testWriteReplace {

public static void main(String[] args) {

//创建File对象

File file=new File("D:\\3.txt");

try {

//创建一个ObjectOutPutStream输出流

ObjectOutputStream oos=new ObjectOutputStream

(new FileOutputStream(file));

Teacher t1=new Teacher("徐才厚", 19);

//序列化teacher对象

oos.writeObject(t1);

ObjectInputStream ois=new ObjectInputStream

(new FileInputStream(file));

ArrayList<Object>array=(ArrayList<Object>) ois.readObject();

System.out.println(array);

} catch (Exception e) {

// TODO Auto-generated catch block

e.printStackTrace();

}

}

}

与writeReplace()方法相对的是readResolve()方法

这个方法紧接着readObject()之后被调用,该方法的返回值会代替原来反序列化的对象,而原来readobject()反序列化的对象将会被立即丢弃。readResolve()在序列化单例类,枚举类时,有用。
这个的意思是我们在序列化和反序列单例时,应该得到得是同一份对象。但是如果不重写readResolve()方法,readObject()方法会返回一个不同的对象,此时在执行readResolve()时,此时重写readresolve()

会返回重写后的一个对象,原有对象丢弃。
public class Orientation implements Serializable{

public static final Orientation HORIZONTAL=new Orientation(1);

public static final Orientation VERTICAL=new Orientation(2);

private int value;

public Orientation(int value) {

this.value = value;

}

/*****

功能测试:readResolve()方法会在readObject()之后被调用

该方法的返回值将会代替原来的反序列化的对象,而原来readObject()

反序列化的对象将会立即丢弃。它在序列化单例类和枚举类时尤其有用。

这只在把数据往磁盘中写时,起作用。
* *******/

private Object readResolve()throws ObjectStreamException{

if(value==1){

return HORIZONTAL;

}

if(value==2){

return VERTICAL;

}

return null;

}

}

public class testOrientation {

public static void main(String[] args) throws Exception{

File file=new File("D:\\4.txt");

ObjectOutputStream oos=new

ObjectOutputStream(new FileOutputStream(file));

oos.writeObject(Orientation.HORIZONTAL);

ObjectInputStream ois=new

ObjectInputStream(new FileInputStream(file));

Object obj=ois.readObject();

System.out.println(obj==Orientation.HORIZONTAL); //打印true.

}

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: