java基本I/O系列--ObjectInputStream 和 ObjectOutputStream 介绍

来源:互联网 发布:java向多人发邮件 编辑:程序博客网 时间:2024/06/04 19:32

转载自:http://www.cnblogs.com/skywang12345/p/io_01.html
FYI
ObjectInputStream 和 ObjectOutputStream 的作用是,对基本数据和对象进行序列化操作支持。
创建“文件输出流”对应的ObjectOutputStream对象,该ObjectOutputStream对象能提供对“基本数据或对象”的持久存储;当我们需要读取这些存储的“基本数据或对象”时,可以创建“文件输入流”对应的ObjectInputStream,进而读取出这些“基本数据或对象”。
注意: 只有支持 java.io.Serializable 或 java.io.Externalizable 接口的对象才能被ObjectInputStream/ObjectOutputStream所操作!

ObjectOutputStream 函数列表

// 构造函数

ObjectOutputStream(OutputStream output)// public函数void     close()void     defaultWriteObject()void     flush()ObjectOutputStream.PutField     putFields()void     reset()void     useProtocolVersion(int version)void     write(int value)void     write(byte[] buffer, int offset, int length)void     writeBoolean(boolean value)void     writeByte(int value)void     writeBytes(String value)void     writeChar(int value)void     writeChars(String value)void     writeDouble(double value)void     writeFields()void     writeFloat(float value)void     writeInt(int value)void     writeLong(long value)final void     writeObject(Object object)void     writeShort(int value)void     writeUTF(String value)void     writeUnshared(Object object)

ObjectInputStream 函数列表

// 构造函数

ObjectInputStream(InputStream input)int     available()void     close()void     defaultReadObject()int     read(byte[] buffer, int offset, int length)int     read()boolean     readBoolean()byte     readByte()char     readChar()double     readDouble()ObjectInputStream.GetField     readFields()float     readFloat()void     readFully(byte[] dst)void     readFully(byte[] dst, int offset, int byteCount)int     readInt()String     readLine()long     readLong()final Object     readObject()short     readShort()String     readUTF()Object     readUnshared()int     readUnsignedByte()int     readUnsignedShort()synchronized void     registerValidation(ObjectInputValidation object, int priority)int     skipBytes(int length)

演示程序

import java.io.*;import java.util.Arrays;import java.util.HashMap;/** * 对象流演示 * ObjectInputStream 和 ObjectOutputStream 测试程序 * <p/> * 注意:通过ObjectInputStream, ObjectOutputStream操作的对象,必须是实现了Serializable或Externalizable序列化接口的类的实例。 */public class ObjectStreamTest {    private static String FILENAME = "t.tmp";    public static void main(String[] args) throws IOException, ClassNotFoundException {        //baseapi();        testWriteApis();        testReadApis();    }    public static void testReadApis() {        try {            ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream(FILENAME));            byte readByte = objectInputStream.readByte();            System.out.printf("byte = %s \n", readByte & 0xff);            System.out.printf("int = %d \n", objectInputStream.readInt());            System.out.printf("char = %s \n", objectInputStream.readChar());            System.out.printf("boolean = %s \n", objectInputStream.readBoolean());            System.out.printf("hashmap = %s \n", objectInputStream.readObject());            Box box = (Box) objectInputStream.readObject();            System.out.printf("box = %s \n", box);            objectInputStream.close();        } catch (IOException e) {            e.printStackTrace();        } catch (ClassNotFoundException e) {            e.printStackTrace();        }    }    public static void testWriteApis() {        try {            ObjectOutputStream objectOutputStream = new ObjectOutputStream(new FileOutputStream(FILENAME));            objectOutputStream.writeByte((byte) 100);            objectOutputStream.writeInt(200);            //  objectOutputStream.writeInt(200);            objectOutputStream.writeChar('a');            objectOutputStream.writeBoolean(true);            HashMap hashMap = new HashMap();            hashMap.put("one", 1);            hashMap.put("two", 2);            hashMap.put("three", 3);            objectOutputStream.writeObject(hashMap);            Box box = new Box();            box.setAge(11);            box.setName("iii");            box.setTmpname("ttt");            objectOutputStream.writeObject(box);            objectOutputStream.close();        } catch (IOException e) {            e.printStackTrace();        }    }    private static class Box implements Serializable {        private static String staticName = "static";        private String name;        private int age;        private transient String tmpname;        public static String getStaticName() {            return staticName;        }        public static void setStaticName(String staticName) {            Box.staticName = staticName;        }        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;        }        public String getTmpname() {            return tmpname;        }        public void setTmpname(String tmpname) {            this.tmpname = tmpname;        }        @Override        public String toString() {            return "Box{" +                    "name='" + name + '\'' +                    ", age=" + age +                    ", tmpname='" + tmpname + '\'' +                    '}';        }    }/*    private static void baseapi() throws IOException, ClassNotFoundException {        ObjectOutputStream objectOutputStream = new ObjectOutputStream(new FileOutputStream("object.txt"));        Employee[] employees = new Employee[3];        Employee employee1 = new Employee("thushear", 18, 1000);        Employee employee2 = new Employee("thushear", 22, 3000);        Employee manager = new Employee("wang", 33, 11000);        employee2.setManager(manager);        employee1.setManager(manager);        employees[0] = manager;        employees[1] = employee1;        employees[2] = employee2;        objectOutputStream.writeObject(employees);        ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream("object.txt"));        Employee[] employees1 = (Employee[]) objectInputStream.readObject();        System.out.println(Arrays.toString(employees1));        for (Employee employee : employees1) {        }    }*/}

序列化的作用和用途

序列化,就是为了保存对象的状态;而与之对应的反序列化,则可以把保存的对象状态再读出来。
简言之:序列化/反序列化,是Java提供一种专门用于的保存/恢复对象状态的机制。
一般在以下几种情况下,我们可能会用到序列化:
a)当你想把的内存中的对象状态保存到一个文件中或者数据库中时候;
b)当你想用套接字在网络上传送对象的时候;
c)当你想通过RMI传输对象的时候。
我们在介绍序列化定义时,说过“序列化/反序列化,是专门用于的保存/恢复对象状态的机制”。
从中,我们知道:序列化/反序列化,只支持保存/恢复对象状态,即仅支持保存/恢复类的成员变量,但不支持保存类的成员方法!
但是,序列化是不是对类的所有的成员变量的状态都能保存呢?
答案当然是否定的!
(01) 序列化对static和transient变量,是不会自动进行状态保存的。
transient的作用就是,用transient声明的变量,不会被自动序列化。
(02) 对于Socket, Thread类,不支持序列化。若实现序列化的接口中,有Thread成员;在对该类进行序列化操作时,编译会出错!
这主要是基于资源分配方面的原因。如果Socket,Thread类可以被序列化,但是被反序列化之后也无法对他们进行重新的资源分配;再者,也是没有必要这样实现。

演示程序

/** * Created by thushear  on 2015/8/30. */import java.io.*;import java.net.Socket;/** *  序列化 */public class SerialTest {    static String FILE = "serial.txt";    static String  EXT_FILE = "extserial.txt";    static Serial serial = new Serial("thushear",111,222,333);    public static void main(String[] args) {        testWriteObject();        testReadObject();//        testExtWriteObject();        testWriteExternalObject();        testReadExternalObject();    }    public static void testReadObject() {        try {            ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream(FILE));            Serial serial = (Serial) objectInputStream.readObject();            // Serial{weight=0, name='thushear', age=111,height = 222}   weight 是初始默认值  height是因为static变量公用            // Serial{weight=333, name='thushear', age=111,height = 222}  手动扩展后 transient 和 static  都可以序列化            System.out.printf("serial = %s \n" , serial);            objectInputStream.close();        } catch (IOException e) {            e.printStackTrace();        } catch (ClassNotFoundException e) {            e.printStackTrace();        }    }    public static void testWriteObject() {        try {            ObjectOutputStream objectOutputStream = new ObjectOutputStream(new FileOutputStream(FILE));            objectOutputStream.writeObject(serial);            objectOutputStream.close();        } catch (IOException e) {            e.printStackTrace();        }    }    public static void testExtWriteObject () {        try {            ObjectOutputStream objectOutputStream = new ObjectOutputStream(new FileOutputStream(FILE));            objectOutputStream.writeObject(new ExtSerial());            objectOutputStream.close();        } catch (IOException e) {            e.printStackTrace();        }    }    public static void testWriteExternalObject() {        try {            ObjectOutputStream objectOutputStream = new ObjectOutputStream(new FileOutputStream(EXT_FILE));            objectOutputStream.writeObject(new ExternalSerial("thushear",111));            objectOutputStream.close();        } catch (IOException e) {            e.printStackTrace();        }    }    public static void testReadExternalObject() {        try {            ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream(EXT_FILE));            ExternalSerial externalSerial = (ExternalSerial) objectInputStream.readObject();            System.out.printf("serial = %s \n" , externalSerial);            objectInputStream.close();        } catch (IOException e) {            e.printStackTrace();        } catch (ClassNotFoundException e) {            e.printStackTrace();        }    }}/** * 序列化的第二种方式 实现 Externalizable */class ExternalSerial implements Externalizable {    public ExternalSerial() {    }    private String name ;    private int age ;    public ExternalSerial(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 void writeExternal(ObjectOutput out) throws IOException {        out.writeObject(name);        out.writeInt(age);    }    @Override    public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {        name = (String) in.readObject();        age =  in.readInt();    }    @Override    public String toString() {        return "ExternalSerial{" +                "name='" + name + '\'' +                ", age=" + age +                '}';    }}/** * 资源型的对象无法序列化 * java.io.NotSerializableException: */class ExtSerial implements Serializable {    Thread thread = new Thread(){        @Override        public void run() {            System.out.println("serial thread runs");        }    };    Socket socket = new Socket();}/** * static transient * 实现Serializable接口才可以被序列化 */class  Serial  implements Serializable{    transient int  weight ;    static int height ;    String name ;    int age ;    public Serial( String name, int age , int height , int weight) {        this.weight = weight;        this.name = name;        this.age = age;        this.height = height;    }    /**     * 手动序列化     * @param objectOutputStream     * @throws IOException     */    private void writeObject(ObjectOutputStream objectOutputStream) throws IOException {        objectOutputStream.defaultWriteObject();        objectOutputStream.writeInt(weight);        objectOutputStream.writeInt(height);    }    /**     * 手动序列化     * @param objectInputStream     * @throws IOException     * @throws ClassNotFoundException     */    private void readObject(ObjectInputStream objectInputStream) throws IOException, ClassNotFoundException {        objectInputStream.defaultReadObject();        weight = objectInputStream.readInt();        height = objectInputStream.readInt();    }    public int getWeight() {        return weight;    }    public void setWeight(int weight) {        this.weight = weight;    }    public static int getHeight() {        return height;    }    public static void setHeight(int height) {        Serial.height = height;    }    public Serial(String name, int age) {        this.name = name;        this.age = age;    }    public int getAge() {        return age;    }    public void setAge(int age) {        this.age = age;    }    public String getName() {        return name;    }    public void setName(String name) {        this.name = name;    }    @Override    public String toString() {        return "Serial{" +                "weight=" + weight +                ", name='" + name + '\'' +                ", age=" + age +                ",height = " + height +                '}';    }}

程序说明:

“序列化不会自动保存static和transient变量”,因此我们若要保存它们,则需要通过writeObject()和readObject()去手动读写。
(01) 通过writeObject()方法,写入要保存的变量。writeObject的原始定义是在ObjectOutputStream.java中,我们按照如下示例覆盖即可:
private void writeObject(ObjectOutputStream out) throws IOException{
out.defaultWriteObject();// 使定制的writeObject()方法可以利用自动序列化中内置的逻辑。
out.writeInt(ival); // 若要保存“int类型的值”,则使用writeInt()
out.writeObject(obj); // 若要保存“Object对象”,则使用writeObject()
}
(02) 通过readObject()方法,读取之前保存的变量。readObject的原始定义是在ObjectInputStream.java中,我们按照如下示例覆盖即可:
private void readObject(ObjectInputStream in) throws IOException,ClassNotFoundException{
in.defaultReadObject(); // 使定制的readObject()方法可以利用自动序列化中内置的逻辑。
int ival = in.readInt(); // 若要读取“int类型的值”,则使用readInt()
Object obj = in.readObject(); // 若要读取“Object对象”,则使用readObject()
}

Externalizable和完全定制序列化过程

如果一个类要完全负责自己的序列化,则实现Externalizable接口,而不是Serializable接口。
Externalizable接口定义包括两个方法writeExternal()与readExternal()。需要注意的是:声明类实现Externalizable接口会有重大的安全风险。writeExternal()与readExternal()方法声明为public,恶意类可以用这些方法读取和写入对象数据。如果对象包含敏感信息,则要格外小心。
下面,我们修改之前的SerialTest1.java测试程序;将其中的Box由“实现Serializable接口” 改为 “实现Externalizable接口”。

0 0
原创粉丝点击