`
Franciswmf
  • 浏览: 797345 次
  • 性别: Icon_minigender_1
  • 来自: 上海
文章分类
社区版块
存档分类
最新评论

Serializable Externalizable transient singleton readRsolve()

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

一、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();
		}
	}

}


分享到:
评论

相关推荐

    Java 串行化(序列化)Serializable/Externalizable

    Java 串行化主要通过实现`java.io.Serializable`接口来实现,同时也提供了`java.io.Externalizable`接口来提供更细粒度的控制。 **一、Serializable接口** `Serializable`是Java中的一个标记接口,没有包含任何方法...

    java 对象默认序列化的干预方法

    在Java中,实现`Serializable`接口的类可以被序列化。然而,有时我们可能希望在序列化过程中忽略某些敏感或临时的成员变量。这就是`transient`关键字的用途。 `transient`关键字用于标记某个成员变量,使其在序列化...

    Singleton

    可以通过实现Serializable接口并重写readResolve()方法来解决这个问题。 此外,Singleton模式虽然简单易用,但也有一些缺点,如违背了开闭原则(对扩展开放,对修改关闭),导致程序难以进行单元测试,以及在某些多...

    java.io.Serializable序列化问题

    ### Java.io.Serializable 序列化...通过实现 `Serializable` 接口或 `Externalizable` 接口,可以轻松地实现序列化和反序列化功能。需要注意的是,在实际应用中还需要考虑序列化的效率、安全性以及版本兼容性等问题。

    Java_transient关键字

    ### Java中的transient关键字详解 在Java编程语言中,`transient`关键字是一个非常重要的概念,主要用于对象序列化过程中对特定变量的控制。当一个类实现了`Serializable`接口时,其对象可以被序列化为一个持久化的...

    java关键字transient

    4. 如果一个类的所有实例变量都是`transient`,那么该类就没有必要实现`Serializable`接口,因为序列化没有任何意义。 **示例代码** 下面是一个简单的例子,展示了如何使用`transient`关键字: ```java import ...

    Intent传递对象Serializable

    本教程将详细讲解如何通过Serializable接口来实现Intent对象的传递。 首先,了解Serializable接口。在Java中,Serializable是用于序列化和反序列化的接口。当一个类实现了这个接口,它的实例就可以被转化为一串字节...

    可序列化接口Serializable

    在Java编程语言中,`Serializable`接口是一个非常重要的概念,它是实现对象持久化的关键。本文将深入探讨`Serializable`接口的细节,以及与其相关的高级知识。 `Serializable`接口是Java中的一个标记接口,没有包含...

    序列化 serializable demo

    例如,`MySerializable.java`和`Product.java`两个文件可能分别代表实现了`Serializable`接口的类。`MySerializable`可能是自定义的一个示例类,而`Product`可能是表示产品的类,它们都包含了可序列化的属性。 在`...

    轉Serializable至Stream

    在Java编程中,`Serializable`接口是用于对象序列化的重要工具。对象序列化是指将一个对象的状态转换为字节流的过程,以便存储或通过网络进行传输。另一方面,`Stream`通常指的是I/O流,它是Java处理输入/输出数据的...

    Serializable java序列号

    另外,对于包含敏感信息的类,可以通过使用`transient`关键字标记那些不想序列化的字段,因为`transient`字段不会被序列化。 此外,`Serializable`接口没有版本控制机制,当序列化的类结构发生变化(比如增加、删除...

    Serializable在C#中的作用.NET 中的对象序列化

    ### C#中Serializable的作用与对象序列化详解 #### 一、引言 在现代软件开发中,特别是基于.NET框架的应用程序开发中,对象序列化是一项非常重要的技术。它允许将对象的状态转换为一种持久的形式(如文件或网络传输...

    Java关键字transient

    1. **不参与序列化**:当一个类实现了`java.io.Serializable`接口,它的实例可以被序列化。但是,如果类中的某个字段被声明为`transient`,那么这个字段就不会被序列化器处理。即使在序列化和反序列化过程中,这个...

    设计模式之Singleton(单态)

    2. **序列化**:如果Singleton实现了Serializable接口,需处理反序列化时的实例化问题,否则可能会创建多个实例。 3. **测试**:测试Singleton类时,需考虑静态初始化可能导致的问题,可能需要特殊的测试策略。 4. *...

    Java之transient关键字.Java

    当你创建一个可序列化的类(通过实现`Serializable`接口)时,如果你不想某些字段在序列化过程中被保存或在反序列化后恢复,就可以使用`transient`修饰这些字段。 **什么是序列化?** 序列化是将对象的状态转换为...

    java->serializable深入了解

    java->serializable深入了解 java->serializable深入了解 java->serializable深入了解

    bundle传递基本数据,Parcelable类型数据,Serializable类型数据

    本篇将详细介绍如何通过`Bundle` 传递基本数据类型、Parcelable类型数据以及Serializable类型数据。 ### 一、基本数据类型的传递 在Android中,基本数据类型包括int、boolean、float、double、char等。通过`put()`...

    Java transient关键字使用小记

    - 如果一个类的所有实例字段都是`transient`的,那么这个类就没有必要实现`Serializable`接口,因为序列化将没有任何意义。 - 在处理`transient`变量时,开发者通常需要自己管理这些变量的状态,例如在反序列化后...

    Android序列化——Serializable与Parcelable

    本文将深入探讨两种主要的序列化方式:Serializable和Parcelable,并比较它们的优缺点以及适用场景。 首先,我们来了解什么是序列化。序列化是将对象的状态转换为可存储或可传输的形式的过程。在Android中,这个...

Global site tag (gtag.js) - Google Analytics