250 - 对象流

对象流:ObjectInputStream , ObjectOutputStream

【1】对象流:ObjectInputStream,ObjectInputStream

用于存储和读取基本数据类型数据或对象的处理流。

它的强大之处就是可以把Java中的对象写入到数据源中,也能把对象从数据源中还原回来。

其实就是:

【2】序列化和反序列化

        ObjectOutputStream 类 : 把内存中的Java对象转换成平台无关的二进制数据,从而允许把这种二进制数据持久地保存在磁盘上,或通过网络将这种二进制数据传输到另一个网络节点。---->序列化

        用ObjectInputStream类 : 当其它程序获取了这种二进制数据,就可以恢复成原来的Java对象。---->  反序列化

【3】代码:操作字符串对象

首先将一个字符串对象写到文件中去:----> 序列化

package test7_Object_stream;

import java.io.*;

/**
 * @Auther: zhoulz
 * @Description: test7_Object_stream
 * @version: 1.0
 */
public class Test1 {
    public static void main(String[] args) throws IOException {
        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(new File("d:\\Demo3.txt")));
        //将内存中的字符串写出到文件中:
        oos.writeObject("你好周");

        //关闭流
        oos.close();
    }
}

查看文件:

 我们看不懂文件的内容,但是程序是可以看懂的。

所以可以写一个程序读文件中内容:—> 反序列化

代码示例:

package test7_Object_stream;

import java.io.*;

/**
 * @Auther: zhoulz
 * @Description: test7_Object_stream
 * @version: 1.0
 */
public class Test2 {
    public static void main(String[] args) throws IOException, ClassNotFoundException {
        //将文件中保存的字符串 读入到 内存:
        ObjectInputStream ois = new ObjectInputStream(new FileInputStream(new File("d:\\Demo3.txt")));
       //读取:
        //Object o = ois.readObject();
        //因为提前知道是字符串,所以可整体转为字符串类型
        String s = (String)(ois.readObject());
        System.out.println(s);

        //关闭流
        ois.close();
    }
}

结果:

 上面是:操作字符串对象

接下来:

【4】代码:操作自定义类的对象

自定义的Person类:

package test7_Object_stream;

/**
 * @Auther: zhoulz
 * @Description: test7_Object_stream
 * @version: 1.0
 */
public class Person {
    private String name;
    private int 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;
    }
    
    public Person() {
    }

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

测试类:

package test7_Object_stream;

import java.io.*;

/**
 * @Auther: zhoulz
 * @Description: test7_Object_stream —— 操作自定义类的对象
 * @version: 1.0
 */
public class Test3 {
    public static void main(String[] args) throws IOException {
        //序列化:将内存中对象 ---> 文件
        //有一个对象
        Person p = new Person("lili",20);
        //有对象流:
        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(new File("d:\\Demo4.txt")));
        //向外写:
        oos.writeObject(p);

        //关闭流
        oos.close();
    }
}

运行的时候发现出现异常: 

出现异常的原因:

你想要序列化的那个对象对应的类,必须要实现一个接口

接口内部,什么都没有,这种接口叫 标识接口。 

起到标识作用,标识什么呢?

:只要实现这个接口的类的对象才能序列化,否则不可以。 

解决办法:将Person 实现这个标识接口就可以。

 即:

 测试:发现序列化成功,Person具备了序列化的能力。

        这个二进制数据我们看不懂,但是程序可以看懂,所以我们可以用程序实现 反序列化操作:

将这个对象 恢复到内存中来:

代码示例:

package test7_Object_stream;

import java.io.*;

/**
 * @Auther: zhoulz
 * @Description: test7_Object_stream —— 反序列化
 * @version: 1.0
 */
public class Test3_2 {
    public static void main(String[] args) throws IOException, ClassNotFoundException {
        ObjectInputStream ois = new ObjectInputStream(new FileInputStream(new File("d:\\Demo4.txt")));
        //读入内存:
        //Object o = ois.readObject();
        //知道是Person类型,所以直接转换:
        Person p = (Person)(ois.readObject());
        System.out.println(p.toString());
        //结果;test7_Object_stream.Person@4dd8dc3 —— 因为没有重写toString()方法

        //关闭流:
        ois.close();
    }
}

结果:(因为我们没有重写toString方法)

 证明了反序列化成功:   将二进制数据 ——> 内存

【5】serialVersionUID

凡是实现Serializable接口(标识接口)的类都有一个表示序列化版本标识符的静态常量:

➢private static final long serialVersionUID;

➢serialVersionUID用来表明类的不同版本间的兼容性。简言之,其目的是以序列化对象进行版本控制,有关各版本反序加化时是否兼容。

➢如果类没有显示定义这个静态变量,它的值是Java运行时环境根据类的内部细节自动生成的。若类的实例变量做了修改,serialVersionUID 可能发生变化。故建议,显式声明。

➢简单来说,Java的序列化机制是通过在运行时判断类的serialVersionUID来验证版本一致性的。在进行反序列化时,JVM会把传来的字节流中的serialVersionUID与本地相应实体类的serialVersionUID进行比较,如果相同就认为是一致的,可以进行反序列化,否则就会出现序列化版本不一致的异常。(InvalidCastException)

我现在在Person类中加入toString方法:

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

再次运行测试类:

出现异:

 出现异常的原因:

 解决:给这个类 加入一个 序列号:serialVersionUID 

结果:

另注:

针对以上加入toString()方法后,出现运行报错的问题:

先重新进行序列化,然后再进行反序列化 —— 则可以正常运行。 ???

 【6】IDEA中配置序列化版本号

 在Person类上:alt+enter:

 回车即可生成:

 【7】序列化细节

(1)被序列化的类的内部的所有属性,必须是可序列化的;

        (基本数据类型都是可序列化的)

 

 (2)static,transient修饰的属性 不可以被序列化。

 结果:

 想要保护的属性可以用 transient修饰 ;

静态的,被这些类共享的属性,则用static 修饰。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值