最新公告
  • 欢迎您光临立业阁,本站秉承服务宗旨 履行“站长”责任,销售只是起点 服务永无止境!立即加入我们
  • Java之对象的序列化和反序列化_Java教程


    对象的序列化和反序列化

    1)对象序列化,就是将Object对象转换成byte序列,反之叫对象的反序列化。

    2)序列化流(ObjectOutputStream),是字节的过滤流—— writeObject()方法

    反序列化流(ObjectInputStream)—— readObject()方法

    3)序列化接口(Serializable)

    对象必须实现序列化接口,才能进行序列化,否则将出现异常。

    注:这个接口,没有任何方法,只是一个【标准】

    一、最基本的序列化和反序列过程

    序列化和反序列都是以Object对象进行操作的,这里通过一个简单的案例来给大家演示一下对象序列化和反序列化的过程。

    1、新建一个Student类(测试类)

    注意:需要实现序列化接口的类才能进行序列化操作!!

    @SuppressWarnings("serial")
    public class Student implements Serializable{
        private String stuno;//id
        private String stuna;//姓名
        private int stuage;//年龄
        public String getStuno() {
            return stuno;
        }
        public void setStuno(String stuno) {
            this.stuno = stuno;
        }
        public String getStuna() {
            return stuna;
        }
        public void setStuna(String stuna) {
            this.stuna = stuna;
        }
        public Student() {
            super();
            // TODO Auto-generated constructor stub
        }
        public Student(String stuno, String stuna, int stuage) {
            super();
            this.stuno = stuno;
            this.stuna = stuna;
            this.stuage = stuage;
        }
        @Override
        public String toString() {
            return "Student [stuno=" + stuno + ", stuna=" + stuna + ", stuage=" + stuage + "]";
        }
        public int getStuage() {
            return stuage;
        }
        public void setStuage(int stuage) {
            this.stuage = stuage;
        }
    }

    2、将Student类的实例序列化成文件

    基本操作步骤如下:

    1)、指定序列化保存的文件

    2)、构造ObjectOutputStream类

    3)、构造一个Student类

    4)、使用writeObject方法序列化

    5)、使用close()方法关闭流

    String file="demo/obj.dat";
            //对象的序列化
            ObjectOutputStream oos=new ObjectOutputStream(
                    new FileOutputStream(file));
            //把Student对象保存起来,就是对象的序列化
            Student stu=new Student("01","mike",18);
            //使用writeObject方法序列化
            oos.writeObject(stu);
            oos.close();

    运行结果:可以看到demo目录下生成了obj.dat的序列化文件

    3、将文件反序列化读出Student类对象

    基本操作步骤如下:

    1)、指定反序列化的文件

    2)、构造ObjectInputStream类

    3)、使用readObject方法反序列化

    1)、使用close方法关闭流

    String file="demo/obj.dat";
            ObjectInputStream ois =new ObjectInputStream(
                    new FileInputStream(file));
            //使用readObject()方法序列化
            Student stu=(Student)ois.readObject();//强制类型转换
            System.out.println(stu);
            ois.close();

    运行结果:

    注意:在文件反序列化时,readObject方法取出的对象默认都是Object类型,必须强制转换为相应的类型。

    二、transient及ArrayList源码分析

    在日常编程过程中,我们有时不希望一个类所有的元素都被编译器序列化,这时该怎么办呢?

    Java提供了一个transient关键字来修饰我们不希望被jvm自动序列化的元素。下面简单来讲解一下这个关键字。

    transient 关键字:被transient修饰的元素,该元素不会进行jvm默认的序列化,但可以自己完成这个元素的序列化。

    注意:

    1)在以后的网络编程中,如果有某些元素不需要传输,那就可以用transient修饰,来节省流量;对有效元素序列化,提高性能。

    2)可以使用writeObject自己完成这个元素的序列化。

    ArrayList就是用了此方法进行了优化操作。ArrayList最核心的容器Object[] elementData使用了transient修饰,但是在writeObject自己实现对elementData数组的序列化。只对数组中有效元素进行序列化。readObject与之类似。

    ————–自己序列化的方式—————

    在要序列化的类中加入两个方法(这两个方法都是从ArrayList源码中提取出来的,比较特殊的两个方法):

    private void writeObject(java.io.ObjectOutputStream s) throws java.io.IOException{
            s.defaultWriteObject();//把jvm能默认序列化的元素进行序列化操作
            s.writeInt(stuage);//自己完成被transient修饰的元素的序列化
        }
        private void readObject(java.io.ObjectInputStream s) throws java.io.IOException,ClassNotFoundException{
            s.defaultReadObject();//把jvm能默认反序列化的元素进行反序列化操作
            this.stuage=s.readInt();//自己完成stuage的反序列化操作
        }

    加入这两个方法后,即使被transient修饰的元素也能像刚刚那样进行序列化和反序列化了,jvm会自动使用这两个方法帮助我们完成这动作。

    这里又有个问题,为什么还需要手动去完成序列化和反序列化呢,有什么意义呢?

    这个问题得再从ArrayList的源码中去分析:

    可以看出ArrayList源码中自己序列化的目的:ArrayList底层为数组,自己序列化可以过滤数组中无效的元素,只序列化数组中有效的元素,从而提高性能

    因此,实际编程过程中我们可以根据需要来自己完成序列化以提高性能。

    三、序列化中子父类构造函数问题

    在类的序列化和反序列化中,如果存在子类和父类的关系时,序列化和反序列化的过程又是怎么样的呢?

    这里我写一个测试类来测试子类和父类实现序列化和反序列化时构造函数的实现变化。

    public static void main(String[] args) throws IOException {
            // TODO Auto-generated method stub
            String file="demo/foo.dat";
            ObjectOutputStream oos=new ObjectOutputStream(
                    new FileOutputStream(file));
            Foo2 foo2 =new Foo2();
            oos.writeObject(foo2);
            oos.flush();
            oos.close();
        }
    
    }
    class Foo implements Serializable{
        public Foo(){
            System.out.println("foo");
        }
    }
    class Foo1 extends Foo{
        public Foo1(){
            System.out.println("foo1");
        }
        
    }
    class Foo2 extends Foo1{
        public Foo2(){
            System.out.println("foo2");
        }
    }

    运行结果:这是序列化时递归调用了父类的构造函数

    接来下看看反序列化时,是否递归调用父类的构造函数。

    ObjectInputStream ois=new ObjectInputStream(
    new FileInputStream(file));
    Foo2 foo2=(Foo2)ois.readObject();
    ois.close();

    运行结果:控制台没有任何输出。

    那么这个结果是否证明反序列化过程中父类的构造函数就是始终不调用的呢?

    然而不能证明!!

    因为再看下面这个不同的测试例子:

    class Bar {
        public Bar(){
            System.out.println("bar");
        }
    }
    class Bar1 extends Bar implements Serializable{
        public Bar1(){
            System.out.println("bar1");
        }
    }
    class Bar2 extends Bar1{
        public Bar2(){
            System.out.println("bar2");
        }
    }

    我们用这个例子来测试序列化和反序列化。

    序列化结果:

    反序列化结果:没实现序列化接口的父类被显示调用构造函数

    【反序列化时】,向上递归调用构造函数会从【可序列化的一级父类结束】。即谁实现了可序列化(包括继承实现的),谁的构造函数就不会调用。

    总结:

    1)父类实现了serializable接口,子类继承就可序列化。

    子类在反序列化时,父类实现了序列化接口,则不会递归调用其构造函数。

    2)父类未实现serializable接口,子类自行实现可序列化

    子类在反序列化时,父类没有实现序列化接口,则会递归调用其构造函数。

    本文来自 java入门 栏目,欢迎学习!

    以上就是Java之对象的序列化和反序列化的详细内容,更多请关注liyege.cn其它相关文章!

    常见问题FAQ

    免费下载或者VIP会员专享资源能否直接商用?
    本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
    提示下载完但解压或打开不了?
    最常见的情况是下载不完整: 可对比下载完压缩包的与网盘上的容量,若小于网盘提示的容量则是这个原因。这是浏览器下载的bug,建议用百度网盘软件或迅雷下载。若排除这种情况,可在对应资源底部留言,或 联络我们.。
    找不到素材资源介绍文章里的示例图片?
    对于PPT,KEY,Mockups,APP,网页模版等类型的素材,文章内用于介绍的图片通常并不包含在对应可供下载素材包内。这些相关商业图片需另外购买,且本站不负责(也没有办法)找到出处。 同样地一些字体文件也是这种情况,但部分素材会在素材包内有一份字体下载链接清单。
    • 1168会员总数(位)
    • 111858资源总数(个)
    • 2本周发布(个)
    • 0 今日发布(个)
    • 244稳定运行(天)

    提供最优质的资源集合

    立即查看 了解详情
    冀ICP备19022365号-1 百度地图

    [email protected]

    立业阁(www.liyege.cn)免费提供wordpress主题模板、dedecms模板、帝国cms模板、小说网站源码、电影网站源码以及网络技术分享,建站源码,小说模板,电影模板,网赚教程,VPS推荐