Io流---对象流与随机流

对象流:

ObjectInputStream和OjbectOutputSteam

对象流的作用

用于存储和读取基本数据类型数据或对象的处理流。它的强大之处就是可 以把Java中的对象写入到数据源中,也能把对象从数据源中还原回来。

 

序列化和反序列化

 序列化:用ObjectOutputStream类保存基本类型数据或对象的机制 

 反序列化:用ObjectInputStream类读取基本类型数据或对象的机制

 

对象流的注意点:

 ObjectOutputStream和ObjectInputStream不能序列化static和transient修 饰的成员变量

 

 

对象的序列化 

对象序列化机制允许把内存中的Java对象转换成平台无关的二进制流,从 而允许把这种二进制流持久地保存在磁盘上,或通过网络将这种二进制流传 
  输到另一个网络节点。//当其它程序获取了这种二进制流,就可以恢复成原 来的Java对象 序列化的好处在于可将任何实现了Serializable接口的对象转化为字节数据, 使其在保存和传输时可被还原 序列化是 RMI(Remote Method Invoke – 远程方法调用)过程的参数和返 回值都必须实现的机制,而 RMI 是 JavaEE 的基础。因此序列化机制是 JavaEE 平台的基础 如果需要让某个对象支持序列化机制,则必须让对象所属的类及其属性是可 序列化的,为了让某个类是可序列化的,该类必须实现如下两个接口之一。 否则,会抛出NotSerializableException异常 Serializable Externalizable

 

 

对象序列化的版本标识符

凡是实现Serializable接口的类都有一个表示序列化版本标识符的静态变量:     
    private static final long serialVersionUID; 
    serialVersionUID用来表明类的不同版本间的兼容性。简言之,其目的是以序列化对象 进行版本控制,有关各版本反序列化时是否兼容。 
    如果类没有显示定义这个静态常量,它的值是Java运行时环境根据类的内部细节自 动生成的。若类的实例变量做了修改,
      serialVersionUID 可能发生变化。故建议, 显式声明。

   简单来说,Java的序列化机制是通过在运行时判断类的serialVersionUID来验 证版本一致性的。在进行反序列化时,JVM会把传来的字节流中的

     serialVersionUID与本地相应实体类的serialVersionUID进行比较,如果相同 就认为是一致的,可以进行反序列化,否则就会出现序列化版本不一致的异 常。(InvalidCastException)

 

 

简单的说为何实现了Serializable接口的对象要声明一个版本标识符

序列化的SerialVersionId如果不自定义的一个的话,在创建的时候也会自动生成一个,如果我们定义了一个类
没有自定义SerialVersionId然后序列化之后会自动生成一个id值,但是在我们反序列化之后也会自动生成一个值,这两个标识的Id值
不同,可能会导致对象的值不同,有可能反序列化后的类的对象和之前序列化的对象值不同,所以还是我们自定义一个确定的值好点

 

Static 和transient 修饰的变量是不可以被序列化的,修饰的变量序列化之后是不显示的  所以不能被序列化

使用对象流序列化对象

若某个类实现了 Serializable 接口,该类的对象就是可序列化的: 
    创建一个 ObjectOutputStream 
    调用 ObjectOutputStream 对象的 writeObject(对象) 方法输出可序列化对象         
    注意写出一次,操作flush()一次  
反序列化 
         创建一个 ObjectInputStream 
         调用 readObject() 方法读取流中的对象 
         强调:如果某个类的属性不是基本数据类型或 String  类型,而是另一个 引用类型,那么这个引用类型必须是可序列化的,否则拥有该类型的 Field 的类也不能序列化

 

序列化写入

序列化过程:将内存中的java对象保存到磁盘中或通过网络传输出去
使用ObjectOutputStream实现
    @Test
    public void TestOne(){
        ObjectOutputStream ops = null;
        try {
            // 造出对象流,操作字节流
            ops = new ObjectOutputStream(new FileOutputStream("object.dba"));  // 造流
            // 操作数据
            // 写入两个String对象
            ops.writeObject(new String("老王"));
            ops.flush();  // 每一次的写出要操作一次flush操作刷新内存
            ops.writeObject(new String("在你家"));
            ops.flush();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            // 关闭流
            if(ops != null){
                try {
                    ops.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }

    }

 

 

反序列化读出

 

  /*
    反序列化将磁盘文件中的对象还原为内存中的一个java对象
    使用ObjectInputStream来实现
     */

    @Test
    public void TestTwo(){
        ObjectInputStream ois = null;
        try {
            ois = new ObjectInputStream(new FileInputStream("object.dba"));

            Object obj = ois.readObject(); // 因为是使用一个对象流操作对象数据 所以用readObject
            String  str = (String) obj;
            Object obj1 = ois.readObject(); // 因为文件写入了两个String对象那么我们想取几个就要写几个对象来接收
            String  str1 = (String) obj1;
            System.out.println(str);
            System.out.println(str1);
        } catch (IOException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } finally {
            if(ois != null){
                try {
                    ois.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }

    }

 

反序列化读取的时候要一一对象序列化进去的值,当序列化写入3个String那么反序列化读取的时候想要读取第3个也要把前两个先读取了

 

 

 

 

自定义序列化类:

 * 1.需要实现接口:Serializable
 * 2.当前类提供一个全局常量:serialVersionUID
 * 3.除了当前Person类需要实现Serializable接口之外,还必须保证其内部所有属性
 *   也必须是可序列化的。(默认情况下,基本数据类型可序列化)

 

SerialVersionUId 是一个序列化类的唯一标识符,在自定义序列化类的时候必须要自定义一个SerialVersionUID标识符,为了确保反序列化后的对象和序列化写进去的是同一个

 

序列化Person类

package June.JuneSixteen.JuneSixteenAfternoon;

import java.io.Serializable;


/**
 *  * Person需要满足如下的要求,方可序列化
 *  * 1.需要实现接口:Serializable
 *  * 2.当前类提供一个全局常量:serialVersionUID
 *  * 3.除了当前Person类需要实现Serializable接口之外,还必须保证其内部所有属性
 *  *   也必须是可序列化的。(默认情况下,基本数据类型可序列化)
 *  *
 *  *
 *  * 补充:ObjectOutputStream和ObjectInputStream不能序列化static和transient修饰的成员变量
 */
public class JuneSixteenAfternoonPerson implements Serializable {

//    public static final long serialVersionUID = 4742422L; // 建立唯一的序列标识符
    public static final long serialVersionUID = 475463534532L;
    private String name;
    private int age;
    private int id;

    @Override
    public String toString() {
        return "JuneSixteenAfternoonPerson{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", id=" + id +
                '}';
    }

    public String getName() {
        return name;
    }

    public JuneSixteenAfternoonPerson(String name, int age, int id) {
        this.name = name;
        this.age = age;
        this.id = id;
    }

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

    public int getAge() {
        return age;
    }

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

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }
}
序列化Person类

 

 

将序列化Person类序列化存储

    @Test
    public void TestFour(){
        ObjectOutputStream os = null;
        try {
            os = new ObjectOutputStream(new FileOutputStream("object.cc"));  // 指定存储文件
            os.writeObject(new JuneSixteenAfternoonPerson("老李头",17,001)); //创建序列化对象并存储
            os.flush();  // 每一次存储都要刷新
            os.writeObject(new String("老王不在"));
            os.flush();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if(os != null){
                try {
                    os.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
存储序列化类

 

 

反序列化读取

    @Test
    public void TestFive(){
        ObjectInputStream oi = null;
        try {
            oi = new ObjectInputStream(new FileInputStream("object.cc"));
            JuneSixteenAfternoonPerson person = (JuneSixteenAfternoonPerson) oi.readObject();  //指定读取的内容
            Object object = oi.readObject();
            System.out.println(object);
            System.out.println(person);
        } catch (IOException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } finally {
            if(oi != null){
                try {
                    oi.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
反序列化读取

 

 

 

切记

序列化类要实现接口Serialiable并定义
    public static final long serialVersionUID 的值 

如果内部有其它的类 也要实现序列化接口 Serialiable 

 

 

 

 

 

 

 

 

 

 

.

 

posted @ 2020-06-16 17:26  可爱的红领巾  阅读(269)  评论(0)    收藏  举报