Serializable Externalizable transient singleton readRsolve()

java序列化的2个可实现接口Serializable、 Externalizable相关
参考博客:
[url]http://blog.csdn.net/dreamtdp/article/details/15378329[/url]

一、Serializable demo
public enum Gender {

MALE,
FEMALE

}


public class Person implements Serializable{

private String name;
private Integer age;
transient private Gender gender; /*transient指定要忽略序列化的字段*/

public Person(){
System.out.println("without args constructor");
}

public Person(String name,Integer age,Gender gender){
System.out.println("with args constructor");
this.name=name;
this.age=age;
this.gender=gender;
}

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

public Integer getAge() {
return age;
}

public void setAge(Integer age) {
this.age = age;
}

public Gender getGender() {
return gender;
}

public void setGender(Gender gender) {
this.gender = gender;
}

@Override
public String toString() {
return "重写toString()方法输出Person [name=" + name + ", age=" + age + ", gender=" + gender + "]";
}
/**
* 对于上述已被声明为transitive的字段age,除了将transitive关键字去掉之外,
*是否还有其它方法能使它再次可被序列化?方法之一就是在Person类中添加两个方法:writeObject()与readObject(),如下所示:
*必须注意地是,writeObject()与readObject()都是private方法,那么它们是如何被调用的呢?毫无疑问,是使用反射。
* @throws IOException
*/
private void writeObject(ObjectOutputStream oos) throws IOException{
oos.defaultWriteObject();
oos.writeObject(gender);
}

private void readObject(ObjectInputStream ois) throws ClassNotFoundException, IOException{
ois.defaultReadObject();
gender=(Gender) ois.readObject();
}


public class TestSerializable {

public static void main(String[] args) {
File file=new File("person.out");
//写
try {
ObjectOutputStream oos=new ObjectOutputStream(new FileOutputStream(file));
Person person=new Person("tom",22,Gender.FEMALE);
oos.writeObject(person);
oos.close();
System.out.println("========================");

} catch (FileNotFoundException e) {
System.out.println("找不到文件");
e.printStackTrace();
} catch (IOException e) {
System.out.println("执行ObjectOutputStream 报错。");
e.printStackTrace();
}

//读
try {
ObjectInputStream ois=new ObjectInputStream(new FileInputStream(file));
Object newPerson = ois.readObject();
ois.close();
System.out.println("newPerson="+newPerson);
} catch (ClassNotFoundException e) {
System.out.println("ObjectInputStream找不到类");
e.printStackTrace();
} catch (IOException e) {
System.out.println("ObjectInputStream其他异常");
e.printStackTrace();
}
/**
*此时必须注意的是,当重新读取被保存的Person对象时,并没有调用Person的任何构造器,看起来就像是直接使用字节将Person对象还原出来的。
*当Person对象被保存到person.out文件中之后,我们可以在其它地方去读取该文件以还原对象,但必须确保该读取程序的CLASSPATH中
*包含有Person.class(哪怕在读取Person对象时并没有显示地使用Person类,如上例所示),否则会抛出ClassNotFoundException。
*/



}

}


二、Externalizable

public class Student implements Externalizable{

private String name;
private int age;
transient private Gender gender;
/**
* 使用Externalizable接口时,该方法必须声明,且为public.
* 若使用Externalizable进行序列化,当读取对象时,会调用被序列化类的无参构造器去创建一个新的对象,
* 然后再将被保存对象的字段的值分别填充到新对象中。这就是为什么在此次序列化过程中Person类的无参构造器会被调用。
* 由于这个原因,实现Externalizable接口的类必须要提供一个无参的构造器,且它的访问权限为public。
*/
public Student() {
System.out.println("Student without args constructor");
}

public Student(String name, int age, Gender gender) {
System.out.println("Student with args constructor");
this.name = name;
this.age = age;
this.gender = gender;
}


private void writeObject(ObjectOutputStream oos) throws IOException{
oos.defaultWriteObject();
oos.writeObject(gender);
}

private void readObject(ObjectInputStream ois) throws ClassNotFoundException, IOException{
ois.defaultReadObject();
gender=(Gender) ois.readObject();
}
/**
* Externalizable必须手动写读取内容
*/
@Override
public void readExternal(ObjectInput arg0) throws IOException, ClassNotFoundException {
name=(String) arg0.readObject();
age=arg0.readInt();
}
/**
* Externalizable必须手动写输出内容
*/
@Override
public void writeExternal(ObjectOutput arg0) throws IOException {
arg0.writeObject(name);
arg0.writeInt(age);

}

@Override
public String toString() {
return "Student [name=" + name + ", age=" + age + ", gender=" + gender + "]";
}


}




public class TestExternalizable {

public static void main(String[] args) {
File file=new File("person.out");
//写
try {
ObjectOutputStream oos=new ObjectOutputStream(new FileOutputStream(file));
Student person=new Student("tom",22,Gender.FEMALE);
oos.writeObject(person);
oos.close();
System.out.println("========================");

} catch (FileNotFoundException e) {
System.out.println("找不到文件");
e.printStackTrace();
} catch (IOException e) {
System.out.println("执行ObjectOutputStream 报错。");
e.printStackTrace();
}

//读
try {
ObjectInputStream ois=new ObjectInputStream(new FileInputStream(file));
Object newPerson = ois.readObject();
ois.close();
System.out.println("newPerson="+newPerson);
} catch (ClassNotFoundException e) {
System.out.println("ObjectInputStream找不到类");
e.printStackTrace();
} catch (IOException e) {
System.out.println("ObjectInputStream其他异常");
e.printStackTrace();
}
/**
*此时必须注意的是,当重新读取被保存的Person对象时,并没有调用Person的任何构造器,看起来就像是直接使用字节将Person对象还原出来的。
*当Person对象被保存到person.out文件中之后,我们可以在其它地方去读取该文件以还原对象,但必须确保该读取程序的CLASSPATH中
*包含有Person.class(哪怕在读取Person对象时并没有显示地使用Person类,如上例所示),否则会抛出ClassNotFoundException。
*/



}

}


三、Singleton Class实现 Serializable


public class SingletonPerson implements Serializable {

private String name;
private Integer age;
private Gender gender;

/**
* 对外提供实例的开发方法
* @return
*/
public static SingletonPerson getInstance(){
return instanceHolder.instance;
}
/**
* 内部类
*
*/
private static class instanceHolder{
private static final SingletonPerson instance=new SingletonPerson("Jenny", 30, Gender.FEMALE);
}
/**
* 单例 private修饰
*/
private SingletonPerson() {
System.out.println("1-constructor without arguments");
}
/**
* 单例 private修饰
*/
private SingletonPerson(String name, Integer age, Gender gender) {
System.out.println("2-constructor with arguments");
this.name = name;
this.age = age;
this.gender = gender;
}

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

public Integer getAge() {
return age;
}

public void setAge(Integer age) {
this.age = age;
}

public Gender getGender() {
return gender;
}

public void setGender(Gender gender) {
this.gender = gender;
}

@Override
public String toString() {
return "SingletonPerson [name=" + name + ", age=" + age + ", gender=" + gender + "]";
}
/**
* 值得注意的是,从文件person.out中获取的Person对象与Person类中的单例对象并不相等。
* 为了能在序列化过程仍能保持单例的特性,可以在Person类中添加一个readResolve()方法,
* 在该方法中直接返回Person的单例对象,如下所示:
*/
private Object readResolve(){
/**
* 无论是实现Serializable接口,或是Externalizable接口,
* 当从I/O流中读取对象时,readResolve()方法都会被调用到。
* 实际上就是用readResolve()中返回的对象直接替换在反序列化过程中创建的对象,
* 而被创建的对象则会被垃圾回收掉。
*/
return instanceHolder.instance;
}


}




public class TestSingletonPerson {

public static void main(String[] args) {
try {
File file=new File("singletonPerson.out");
ObjectOutputStream oos=new ObjectOutputStream(new FileOutputStream(file));
oos.writeObject(SingletonPerson.getInstance());//写出
oos.close();
//
ObjectInputStream ois=new ObjectInputStream(new FileInputStream(file));
SingletonPerson singletonPerson=(SingletonPerson) ois.readObject();//读入
ois.close();
//
System.out.println("结果1:"+singletonPerson);
System.out.println(SingletonPerson.getInstance()==singletonPerson);
//false,在SingletonPerson中加入readResolve()方法后即输出true.
//
} catch (Exception e) {
e.printStackTrace();
}
}

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值