您的位置:首页 > 移动开发 > Android开发

浅谈Android中的Serializable 接口

2013-09-24 23:03 387 查看

Object serialization

对于Serializable 接口其实是在JavaSE中就有的,在Android中的用法跟JavaSE的用法一样。允许你将实现了Serializable接口的对象转换为字节序列, 这些字节序列可以被完全存储以备以后重新生成原来的对象。 serialization不但可以在本机做,而且可以经由网络操作(RMI)。 这个好处是很大的----因为它自动屏蔽了操作系统的差异,字节顺序等。 比如,在Window平台生成一个对象并序列化之,然后通过网络传到一台Unix机器上, 然后可以在这台Unix机器上正确地重构这个对象。

Object serialization主要的特性

 Object serialization主要用来支持2种主要的特性:

  1。Java的RMI(remote method invocation)

RMI允许象在本机上一样操作远程机器上的对象 。当发送消息给远程对象时,就需要用到serializaiton机制来发送参数和接收返回直。

 2。Java的JavaBeans

 Bean的状态信息通常是在设计时配置的。Bean的状态信息必须被存起来,以便当程序运行时能恢复 这些状态信息。这也需要serializaiton机制。

 但是Java语言里现在只支持lightweight persistence,就是轻量级持久化, 这是通过serialization机制来实现的。 persistence是指一个对象的生命周期不由程序是否执行来决定, 即使是在程序终止时这个对象也存在。它把一个serializable的对象写到磁盘 (本机或其他机器上的非RAM存储器), 并在程序重新调用时再读取对象到通常的RAM存储器。

 为什么说Java的serialization机制实现的是lightweight persistence?

 因为你必须显式的序列化和反序列化程序里的对象; 而不是直接由一个关键词来定义一个对象是序列化的然后由系统做相应的处理。 

实现的类有

 实现了此接口的类有:String, Integer, Boolean, Long, ArrayList, List, File 等等。

作用和原理

类通过实现 java.io.Serializable 接口以启用其序列化功能;未实现此接口的类将无法使其任何状态序列化或反序列化;可序列化类的所有子类型本身都是可序列化的;序列化接口没有方法或字段,仅用于标识可序列化的语义。

 当java内存有一个对象的时候,我们想把它持久化保存起来,以后又可以从保存的数据中恢复成对象,这种情况经常在java中出现;sun公司为了方便实现这种功能,为用户提供了java.io.Serializable这个接口,这个接口中没有方法(又称为mini接口); 在java编译器编译的时候对这种mini接口的对象进行特殊的编译,如果你的对象实现了serializable接口,那么就可以通过另一个工具ObjectOutputStream的方法writeObject(obj)来存储对象,而不需要具体知道存储该对象的具体细节; 当恢复对象的时候,便可以通过ObjectInputStream.readObject(obj)来恢复对象; 由于对于文件的存储目标是未知的,可以是硬盘也可以是网络上的某个主机,故ObjectInputStream和ObjectOutputStream并不是直接操作硬盘,也不是直接操作网络,而是操作可以直接访问物理设备的流的对象,如FileInputStream和FileOutputStream,即ObjectInputStream和ObjectOutputStream可以将直接进行底层操作的流FileInputStream和FileOutputStream包装起来,形成包装类,或者叫包装流; 在形成包装类之后,对于需要保存的对象,先由包装类的外层将该对象转换为二进制字节,再将这些字节传递给内层可以直接进行物理设备操作的流如FileOutputStream,通过底层流保存到物理设备; 包装的思想:首先,有个物理设备,如硬盘或网络,在内存中会有个流,如FileOutputStream,这个流只能有个write(byte[])方法,该方法写的是字节。而现在要将一个对象写入物理设备,故需要一个类来进行对象到字节的转换,这个转换类就是ObjectInputStream和ObjectOutputStream,通过这两个类转换,将转换后的字节数据交给FileOutputStream来进行物理设备操作。简单地说,就是一个分层的思想,也是“各尽其责”的思想。对象保存到物理设备,这个过程由两层完成,上层只负责将对象转换成字节数据,下层只负责将接收到的字节写入物理设备。 所以包装流(如ObjectOutputStream)并不真正连接到底层物理设备,它起到一个中转的作用,因此它的构造方法一定要传递给它一个与底层设备相关的流,前者是把数据转换完了交给后者去读写物理设备;对于物理设备是什么设备,包装流并不知道,只有传递给它的底层设备相关的流(如FileOutputStream)知道。

这段跟上面的意思差不多

 类通过实现 java.io.Serializable 接口以启用其序列化功能。未实现此接口的类 将无法使其任何状态序列化或反序列化。可序列化类的所有子类型本身都是可 序列化的。序列化接口没有方法或字段,仅用于标识可序列化的语义。 Java的"对象序列化"能让你将一个实现了Serializable接口的对象转换成一 组byte,这样日后要用这个对象时候,你就能把这些byte数据恢复出来,并据 此重新构建那个对象了。 要想序列化对象,你必须先创建一个OutputStream,然后把它嵌进 ObjectOutputStream。这时,你就能用writeObject(
)方法把对象写入 OutputStream了。 writeObject 方法负责写入特定类的对象的状态,以便相应的 readObject 方法可以还原它。通过调用 out.defaultWriteObject 可以调用保 存 Object 的字段的默认机制。该方法本身不需要涉及属于其超类或子类的状 态。状态是通过使用 writeObject 方法或使用 DataOutput 支持的用于基本数 据类型的方法将各个字段写入 ObjectOutputStream 来保存的。 读的时候,你得把InputStream嵌到ObjectInputStream里面,然后再调 用readObject(
)方法。不过这样读出来的,只是一个Object的reference,因

 此在用之前,还得先下传。readObject 方法负责从流中读取并还原类字段。它 可以调用 in.defaultReadObject 来调用默认机制,以还原对象的非静态和非瞬 态字段。

注意事项

 在序列化时,有几点要注意的:

 1:当一个对象被序列化时,只保存对象的非静态成员变量,不能保存任 何的成员方法和静态的成员变量。

 2:如果一个对象的成员变量是一个对象,那么这个对象的数据成员也会 被保存。 

 3:如果一个可序列化的对象包含对某个不可序列化的对象的引用,那么整个序列化操作将会失败,并且会抛出一个NotSerializableException。我们 可以将这个引用标记为transient,那么对象仍然可以序列化 。 项目中可能有许多实体的需要辅助的属性和方法辅助,hibernate中实体bean中所有的非static非@Transient 那么必须使用@Transient注解的属性都可以被持久化,除非你将其注解为@Transient。

 @Transient的作用 : 用于注释pojo对象中的属性,被注释的属性将成为短暂的,不会持久化到数据库的“短暂”属性。

 所有没有定义注解的属性相等于@Basic

 还有我们对某个对象进行序列化时候,往往对整个对象全部序列化了,比如说类里有些数据比较敏感,不希望序列化,一个方法可以用关键字transient来标识,另一个方法我们可以在类里写以下两个方法:

 private   void  readObject(java.io.ObjectInputStream stream)

 throws  IOException, ClassNotFoundException;

 private   void  writeObject(java.io.ObjectOutputStream stream)

 throws  IOException

第一个简单的例子:实现接口

public class Main {

/**
* @param args
*/
public static void main(String[] args) {
MyClass object1 = null;
try {
object1 = new MyClass("Hello", -7, 2.7e10);

System.out.println("object1:" + object1);
// 写入数据
FileOutputStream fos = new FileOutputStream("serial");

ObjectOutputStream oos = new ObjectOutputStream(fos);
oos.writeObject(object1);
oos.flush();
oos.close();
} catch (Exception e) {
System.out.println("Exception during serialization:" + e);
System.exit(0);
}

// Object deserialization
try {
MyClass object2;

FileInputStream fis = new FileInputStream("serial");

ObjectInputStream ois = new ObjectInputStream(fis);

//假如没有实现这个接口会出现异常NotSerializableException
object2 = (MyClass) ois.readObject();
ois.close();
System.out.println("object1=object2" + (object1 == object2));//false
System.out.println("object2:" + object2);
} catch (Exception e) {
System.out.println("Exception during deserialization:" + e);
System.exit(0);
}
}

}

class MyClass implements Serializable {
String s;
int i;
double d;

public MyClass(String s, int i, double d) {
this.s = s;
this.i = i;
this.d = d;
}

public String toString() {
return "s=" + s + ";i=" + i + ";d=" + d;
}

}

第二个简单的例子:没有实现接口

不需要全部都实例化,但是在类中声明了方法。(自己弄得,不知是否正确)
public class Main {
// 不以对象参数传给一个方法,是在这个方法中获取这个对象,再通过这个对象来控制其可调用的方法来显示其中的信息
// (一般情况下,这给类类似与javabean(一个结构))
// 八种基本类型,已经实现了Serializable接口
public static void main(String[] args) throws Exception {
Employee e1 = new Employee(" zhangsan ", 25, 3000.50);
Employee e2 = new Employee(" lisi ", 24, 3200.40);
Employee e3 = new Employee(" wangwu ", 27, 3800.55);

FileOutputStream fos = new FileOutputStream(" employee");
ObjectOutputStream oos = new ObjectOutputStream(fos);

e1.writeObject(oos);
e2.writeObject(oos);
e3.writeObject(oos);
// oos.writeObject(e1);
// oos.writeObject(e2);
// oos.writeObject(e3);
oos.close();
FileInputStream fis = new FileInputStream(" employee");
ObjectInputStream ois = new ObjectInputStream(fis);
// Employee e;
Employee e11, e22, e33;
e11 = e1.readObject(ois);
System.out.println(e11.name + " : " + e11.age + " : " + e11.salary);
e22 = e2.readObject(ois);
System.out.println(e22.name + " : " + e22.age + " : " + e22.salary);
e33 = e3.readObject(ois);
System.out.println(e33.name + " e33.age: " + e33.age + " : "
+ e33.salary);
// for (int i = 0; i < 3; i++) {
// e = (Employee) ois.readObject();
// System.out.println(e.name + " : " + e.age + " : " + e.salary);
// }
}

}

class Employee {
String name;

int age;

double salary;

public Employee(String name, int age, double salary) {
this.name = name;
this.age = age;
this.salary = salary;
}

public void writeObject(java.io.ObjectOutputStream oos) throws IOException {
oos.writeInt(age);
oos.writeUTF(name);
System.out.println(" Write Object ");
}

public Employee readObject(java.io.ObjectInputStream ois)
throws IOException {
age = ois.readInt();
name = ois.readUTF();

System.out.println(" Read Object ");

return new Employee(name, age, 0);//不清楚内部代码(API中提供的源码,如何???)
}

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