IO学霸3 -- Serializable

1. 压缩

CheckedInputStream: GetCheckSum()为任何InputStream()产生校验和。

CheckOutputStream: GetCheckSum()为任何OutputStream产生校验和。

DeflaterOutputStream: 压缩类的基类。

ZipOutputStream: 一个DeflaterOutputStream,用于将数据压缩成Zip文件格式。

GZIPOutputStream: 一个DeflaterOutputStream,用于将数据压缩成GZIP文件格式。

DeflaterInputStream: 解压缩类的基类。

ZipInputStream: 一个DeflaterInputStream,用于解压缩Zip文件格式。

GZIPInputStream: 一个DeflaterInputStream,用于解压缩GZIP文件格式。


2. Serializable

Java的对象序列化将那些实现了Serializable接口的对象转换成一个字节序列,并能够在以后将这个字节序列完全恢复为原来的对象。

这一过程甚至可以通过网络进行,这意味着序列化机制能自动弥补不同操作系统之间的差异。

对象序列化主要有两种特性:一是Java远程调用。使存活于其他计算机上的对象使用起来就像存活于本机上一样,当向远程对象发送消息时,需要通过对象序列化来传输参数和返回值。

二是JavaBeans序列化配置。

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.util.Random;

class Data implements Serializable{
	private int n;
	public Data(int n){
		this.n=n;
	}
	public String toString(){
		return Integer.toString(n);
	}
}


public class Worm implements Serializable {

	private static Random rand = new Random(47);
	private Data[] d = {new Data(rand.nextInt(10)),new Data(rand.nextInt(10)),new Data(rand.nextInt(10))};
	private Worm next;
	private char c;
	
	public Worm(){
		System.out.println("Default constructor");
	}
	public Worm(int i, char x){
		System.out.println("Worm constructor: "+i);
		c=x;
		if(--i>0)
			next = new Worm(i, (char)(x+1));
	}
	public String toString(){
		StringBuffer result = new StringBuffer();
		result.append(c);
		result.append("(");
		for(Data data:d){
			result.append(data);
		}
		result.append(")");
		if(next!=null){
			result.append(next);
		}
		return result.toString();
	}
	
	
	public static void main(String[] args) throws Exception, IOException {
		Worm w = new Worm(6,'a');
		System.out.println("w="+w);
		ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("worm.out"));
		out.writeObject("Worm storage\n");
		out.writeObject(w);
		out.close();
		
		ObjectInputStream in = new ObjectInputStream(new FileInputStream("worm.out"));
		String s = (String) in.readObject();
		Worm w2 = (Worm) in.readObject();
		System.out.println(s+"w2="+w2);
		
		ByteArrayOutputStream bout = new ByteArrayOutputStream();
		ObjectOutputStream out2 = new ObjectOutputStream(bout);
		out2.writeObject("Worm storage\n");
		out2.writeObject(w);
		out2.flush();
		
		ObjectInputStream in2 = new ObjectInputStream(new ByteArrayInputStream(bout.toByteArray()));
		s=(String) in2.readObject();
		Worm w3 = (Worm) in2.readObject();
		System.out.println(s+"w3="+w3);
	}

}
//*Output:
Worm constructor: 6
Worm constructor: 5
Worm constructor: 4
Worm constructor: 3
Worm constructor: 2
Worm constructor: 1
w=a(853)b(119)c(802)d(788)e(199)f(881)
Worm storage
w2=a(853)b(119)c(802)d(788)e(199)f(881)
Worm storage
w3=a(853)b(119)c(802)d(788)e(199)f(881)
*//
对一个Serializable还原中,没有调用任何构造器包括默认构造器,整个对象都是从InputStream中取得数据恢复而来。


Serializable恢复,需要寻找相关的类:

import java.io.FileOutputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;

public class FreezeAlien {

	public static void main(String[] args) throws Exception {
		// TODO Auto-generated method stub
		ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("X.flie"));
		Alien quellek = new Alien();
		out.writeObject(quellek);
	}

}

class Alien implements Serializable{}

//: ../ThawAlien.java
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.ObjectInputStream;

public class ThawAlien {

	public static void main(String[] args) throws IOException, Exception {
		// TODO Auto-generated method stub
		ObjectInputStream in = new ObjectInputStream(new FileInputStream(new File("..", "X.flie")));
		Object o = in.readObject();
		System.out.println(o.getClass());
	}

}

打开文件和读取mystery对象中的内容都要需要Alien的Class对象;而Java虚拟机找不到Alien.class,必须保证JVM能找到相关.class文件。


2.1 序列化控制

Externalizable代替Serializable进行序列化控制。Externalizble接口继承Serializable,并添加writeExternal()和readExternal(),这两个方法在序列化和反序列化还原过程中被自动调用。

import java.io.Externalizable;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectInputStream;
import java.io.ObjectOutput;
import java.io.ObjectOutputStream;

class Blip1 implements Externalizable{
	public Blip1(){
		System.out.println("Blip1 Con");
	}

	@Override
	public void readExternal(ObjectInput arg0) throws IOException,
			ClassNotFoundException {
		System.out.println("Blip1 readExternal");
	}

	@Override
	public void writeExternal(ObjectOutput arg0) throws IOException {
		System.out.println("Blip1 writeExternal");
	}
	
}

class Blip2 implements Externalizable{
	 Blip2(){
		System.out.println("Blip2 Con");
	}

	@Override
	public void readExternal(ObjectInput arg0) throws IOException,
			ClassNotFoundException {
		System.out.println("Blip2 readExternal");
	}

	@Override
	public void writeExternal(ObjectOutput arg0) throws IOException {
		System.out.println("Blip2 writeExternal");
	}
	
}

public class Blips {

	public static void main(String[] args) throws IOException, Exception {
		System.out.println("Constructing Objects:");
		Blip1 b1 = new Blip1();
		Blip2 b2 = new Blip2();
		ObjectOutputStream o = new ObjectOutputStream(new FileOutputStream("Blips.out"));
		System.out.println("Saving Objects:");
		o.writeObject(b1);
		o.writeObject(b2);
		o.close();
		ObjectInputStream in = new ObjectInputStream(new FileInputStream("Blips.out"));
		System.out.println("Recovering b1:");
		b1 = (Blip1) in.readObject();
		System.out.println("Recovering b2:");
		b2 = (Blip2) in.readObject();
		
	}

}
//*Output:
Constructing Objects:
Blip1 Con
Blip2 Con
Saving Objects:
Blip1 writeExternal
Blip2 writeExternal
Recovering b1:
Blip1 Con
Blip1 readExternal
Recovering b2:
Exception in thread "main" java.io.InvalidClassException: com.ld.tij.xfiles.Blip2; com.ld.tij.xfiles.Blip2; no valid constructor
	at java.io.ObjectStreamClass.checkDeserialize(Unknown Source)
	at java.io.ObjectInputStream.readOrdinaryObject(Unknown Source)
	at java.io.ObjectInputStream.readObject0(Unknown Source)
	at java.io.ObjectInputStream.readObject(Unknown Source)
	at com.ld.tij.xfiles.Blips.main(Blips.java:63)

//
因为Blip2构造器不是公有,在恢复Bilp2时候出现异常。

恢复Serializable对象时,对象完全以存储二进制为基础来构造,而不是构造器。

而Externalizable所有普通默认构造器都会被调用,然后调用readExternal()。


transient关键字

某个特定子对象不想让Java序列化自动保存与恢复。

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.util.Date;
import java.util.concurrent.TimeUnit;

public class Logon implements Serializable {
	
	private Date date = new Date();
	private String username;
	private transient String password;
	
	public Logon(String name, String pwd){
		this.username=name;
		this.password=pwd;
	}
	public String toString(){
		return "logon info: \n username: "+username+"\n date: "+date+"\n password: "+password;
	}

	public static void main(String[] args) throws  IOException, Exception {
		Logon a = new Logon("Dog", "lucky");
		System.out.println("Logon a="+a);
		ObjectOutputStream o = new ObjectOutputStream(new FileOutputStream("Logon.out"));
		o.writeObject(a);
		o.close();
		TimeUnit.SECONDS.sleep(1);
		ObjectInputStream in = new ObjectInputStream(new FileInputStream("Logon.out"));
		System.out.println("Recovering objec at "+ new Date());
		a=(Logon) in.readObject();
		System.out.println("logon a="+a);
	}

}
//*Output:
Logon a=logon info: 
 username: Dog
 date: Mon Oct 21 10:51:51 CST 2013
 password: lucky
Recovering objec at Mon Oct 21 10:51:52 CST 2013
logon a=logon info: 
 username: Dog
 date: Mon Oct 21 10:51:51 CST 2013
 password: null
//
Serializable还有一种办法是添加writeObject()和readObject()方法,这样对象一旦被序列化或者反序列化都会自动调用这两个方法。
如果是Externalizable,可以在writeExternal()内部只对需要部分进行序列化即可。


2.2 持久性

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;

class House implements Serializable{}

class Animal implements Serializable{
	private String name;
	private House house;
	Animal(String n, House h){
		name=n;
		house=h;
	}
	public String toString(){
		return name+"["+super.toString()+"], "+house+"\n";
	}
}

public class MyWorld {
	public static void main(String[] args) throws Exception {
		House house = new House();
		List<Animal> animals = new ArrayList<Animal>();
		animals.add(new Animal("Bosco the dog", house));
		animals.add(new Animal("Ralph the hamster", house));
		animals.add(new Animal("Molly the cat", house));
		System.out.println("animals: "+animals);
		
		ByteArrayOutputStream buf1 = new ByteArrayOutputStream();
		ObjectOutputStream o1 = new ObjectOutputStream(buf1);
		o1.writeObject(animals);
		o1.writeObject(animals);

		ByteArrayOutputStream buf2 = new ByteArrayOutputStream();
		ObjectOutputStream o2 = new ObjectOutputStream(buf2);
		o2.writeObject(animals);
		
		ObjectInputStream in1 = new ObjectInputStream(new ByteArrayInputStream(buf1.toByteArray()));
		ObjectInputStream in2 = new ObjectInputStream(new ByteArrayInputStream(buf2.toByteArray()));
		List animal1 = (List) in1.readObject();
		List animal2 = (List) in1.readObject();
		List animal3 = (List) in2.readObject();
		System.out.println("animal1: "+animal1);
		System.out.println("animal2: "+animal2);
		System.out.println("animal3: "+animal3);
	}

}
//*Output:
animals: [Bosco the dog[com.ld.tij.Animal@3d4b7453], com.ld.tij.House@24c21495
, Ralph the hamster[com.ld.tij.Animal@41d5550d], com.ld.tij.House@24c21495
, Molly the cat[com.ld.tij.Animal@1cc2ea3f], com.ld.tij.House@24c21495
]
animal1: [Bosco the dog[com.ld.tij.Animal@28df8ff1], com.ld.tij.House@6d632c2d
, Ralph the hamster[com.ld.tij.Animal@9e97676], com.ld.tij.House@6d632c2d
, Molly the cat[com.ld.tij.Animal@3e60420f], com.ld.tij.House@6d632c2d
]
animal2: [Bosco the dog[com.ld.tij.Animal@28df8ff1], com.ld.tij.House@6d632c2d
, Ralph the hamster[com.ld.tij.Animal@9e97676], com.ld.tij.House@6d632c2d
, Molly the cat[com.ld.tij.Animal@3e60420f], com.ld.tij.House@6d632c2d
]
animal3: [Bosco the dog[com.ld.tij.Animal@219106c7], com.ld.tij.House@38540408
, Ralph the hamster[com.ld.tij.Animal@13d4c61c], com.ld.tij.House@38540408
, Molly the cat[com.ld.tij.Animal@761a626f], com.ld.tij.House@38540408
]

*//
这个例子中,Animal对象包含House类型字段,在main方法中创建一个Animal列表并将其两次序列化,分别推送到不同的流中。

当其被反序列化还原打印时,我们期望反序列化后对象地址与原来不同,但是animal1和animal2地址却相同,包括二者共享House对象的引用。

而恢复animal3时,系统无法知道另一个流内的对象是第一个流内对象的别名,因此产生完全不同的对象网。

如果想保存系统状态,最安全的做法是将其作为 原子 操作进行序列化。 如果我们序列化了某些东西,再去做其他工作,然后才序列化,那么将无法安全保存系统状态。正确的做法应该是:将保存系统状态的所有对象都放在一个单一容器,一个操作中将其直接写出,然后同样一个操作调用,即可恢复。

import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;

abstract class Shape implements Serializable{
	public static final int RED=1, BULE=2, GREEN=3;
	private int xPos, yPos, dimension;
	private static Random rand = new Random(47);
	private static int counter=0;
	public abstract void setColor(int newColor);
	public abstract int getColor();
	
	public Shape(int xVal, int yVal, int dim){
		xPos=xVal;
		yPos=yVal;
		dimension=dim;
	}
	public String toString(){
		return getClass() + "color["+getColor()+"] xPos["+xPos+"] yPos["+yPos+"] dim["+dimension+"]\n";
	}
	public static Shape randomFactory(){
		int xVal = rand.nextInt(100);
		int yVal = rand.nextInt(100);
		int dim = rand.nextInt(100);
		switch(counter++%3){
		default:
		case 0:return new Circle(xVal,yVal,dim);
		case 1:return new Square(xVal,yVal,dim);
		case 2:return new Line(xVal,yVal,dim);
		}
	}
}

class Circle extends Shape{
	private static int color = RED;
	public Circle(int xVal, int yVal, int dim){
		super(xVal,yVal,dim);
	}
	public void setColor(int newColor){
		color = newColor;
	}
	public int getColor(){
		return color;
	}
}
class Square extends Shape{
	private static int color;
	public Square(int xVal, int yVal, int dim){
		super(xVal,yVal,dim);
		color = RED;
	}
	public void setColor(int newColor){
		color = newColor;
	}
	public int getColor(){
		return color;
	}
}
class Line extends Shape{
	private static int color = RED;
	public static void serializeStaticState(ObjectOutputStream os) throws IOException{
		os.writeInt(color);
	}
	public static void deserializeStaticState(ObjectInputStream os) throws IOException{
		color = os.readInt();
	}
	public Line(int xVal, int yVal, int dim){
		super(xVal,yVal,dim);
	}
	public void setColor(int newColor){
		color = newColor;
	}
	public int getColor(){
		return color;
	}
}


public class StoreCADState {

	public static void main(String[] args) throws  IOException {
		List<Class<? extends Shape>> shapeTypes = new ArrayList<Class<? extends Shape>>();
		shapeTypes.add(Circle.class);
		shapeTypes.add(Square.class);
		shapeTypes.add(Line.class);
		
		List<Shape> shapes = new ArrayList<Shape>();
		for(int i=0;i<10;i++){
			shapes.add(Shape.randomFactory());
		}
		
		for(int i=0;i<10;i++){
			((Shape)shapes.get(i)).setColor(Shape.GREEN);
		}
		
		ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("CADState.out"));
		out.writeObject(shapeTypes);
		Line.serializeStaticState(out);
		out.writeObject(shapes);
		System.out.println(shapes);
	}

}
//*Output
[class com.ld.tij.Circlecolor[3] xPos[58] yPos[55] dim[93]
, class com.ld.tij.Squarecolor[3] xPos[61] yPos[61] dim[29]
, class com.ld.tij.Linecolor[3] xPos[68] yPos[0] dim[22]
, class com.ld.tij.Circlecolor[3] xPos[7] yPos[88] dim[28]
, class com.ld.tij.Squarecolor[3] xPos[51] yPos[89] dim[9]
, class com.ld.tij.Linecolor[3] xPos[78] yPos[98] dim[61]
, class com.ld.tij.Circlecolor[3] xPos[20] yPos[58] dim[16]
, class com.ld.tij.Squarecolor[3] xPos[40] yPos[11] dim[22]
, class com.ld.tij.Linecolor[3] xPos[4] yPos[83] dim[6]
, class com.ld.tij.Circlecolor[3] xPos[75] yPos[10] dim[42]
]
*//

恢复对象:

import java.io.*;
import java.util.*;

public class RecoverCADState {
  @SuppressWarnings("unchecked")
  public static void main(String[] args) throws Exception {
    ObjectInputStream in = new ObjectInputStream(
      new FileInputStream("CADState.out"));
    // Read in the same order they were written:
    List<Class<? extends Shape>> shapeTypes =
      (List<Class<? extends Shape>>)in.readObject();
    Line.deserializeStaticState(in);
    List<Shape> shapes = (List<Shape>)in.readObject();
    System.out.println(shapes);
  }
}
//*Output:
[class com.ld.tij.Circlecolor[1] xPos[58] yPos[55] dim[93]
, class com.ld.tij.Squarecolor[0] xPos[61] yPos[61] dim[29]
, class com.ld.tij.Linecolor[3] xPos[68] yPos[0] dim[22]
, class com.ld.tij.Circlecolor[1] xPos[7] yPos[88] dim[28]
, class com.ld.tij.Squarecolor[0] xPos[51] yPos[89] dim[9]
, class com.ld.tij.Linecolor[3] xPos[78] yPos[98] dim[61]
, class com.ld.tij.Circlecolor[1] xPos[20] yPos[58] dim[16]
, class com.ld.tij.Squarecolor[0] xPos[40] yPos[11] dim[22]
, class com.ld.tij.Linecolor[3] xPos[4] yPos[83] dim[6]
, class com.ld.tij.Circlecolor[1] xPos[75] yPos[10] dim[42]
]
*//
可以看到,xPos, yPox, dim的值都被成功保存和恢复,但是static却出现了问题,所有恢复的static都应该是3,只有Line的color恢复正确。

Line中serializeStaticState()和deserializeStaticState()两个方法作为存储和读取过程的一部分被显示的调用。

以上例子正确修改方式:

1)为其他几何图形添加serializeStaticState()和deserializeStaticState()两个方法。

2)移除ArrayList shapeTypes相关代码。

3)添加对几何图形新的序列化和反序列化的显示调用。

因为序列化也会对private保存下来,如果是涉及安全问题还需要标记transient。


IO End~:)









评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值