20210817学习序列化与反序列化

本文介绍了Java中的序列化和反序列化过程,以及泛型在编程中的应用。序列化是将对象状态转换为可存储或传输的形式,反序列化则是恢复对象状态。文章提到,实现Serializable接口是对象序列化的前提,而 transient 关键字用于标记不需要序列化的成员。同时,文章探讨了泛型在提高代码安全性、类型检查和通用代码编写方面的作用,展示了如何使用泛型方法处理不同类型的数组。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

概述

  1. 序列化是指将对象的状态信息转换为可以存储或传输形式的过程.在序列化期间,对象将其当前状态写入到临时或持久性存储区.以后可以通过从存储区中读取或者反序列化对象的状态,重新创建该对象.

  2. 序列化:利用ObjectOutputStream,把对象的信息,按照固定的格式转成一串字节值输出并持久保存到磁盘
    反序列化:利用ObjectInputStream,读取磁盘中之前序列化好的数据,重新恢复成对象

特点

需要序列化的文件必须实现Serializable接口,用来启用序列化功能
不需要序列化的数据可以修饰成static,原因:static资源属于类资源,不随着对象被序列化输出
每一个被序列化的文件都有一个唯一的id,如果没有添加此id,编译器会自动根据类的定义信息计算产生一个
在反序列化时,如果和序列化的版本号不一致,无法完成反序列化
常用与服务器之间的数据传输,序列化成文件,反序列化读取数据
常用使用套接字流在主机之间传递对象
不需要序列化的数据也可以被修饰成transient(临时的),只在程序运行期间在内存中存在,不会被序列化持久保存

package cn.tedu.encoding;

/**
 * 本类用于测试编码转换流
 * @author ZHU
 * @create 17/08/2021 15:33
 */
public class TestEncode {
    public static void main(String[] args) {
        f1();
        f2();
    }
    /**用于测试OutputStreamReader*/
    private static void f2() {
    }

    /**用于测试InputStreamReader*/
    private static void f1() {
    }
}
package cn.tedu.file;

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

/**
 * @author ZHU
 * @create 17/08/2021 10:21
 */
public class TestCopyFile {
    public static void main(String[] args) {
        System.out.println("请输入源文件路径:");
        String f = new Scanner(System.in).nextLine();//--复制啥
        System.out.println("请输入目标文件路径:");
        String t = new Scanner(System.in).nextLine();//--复制到哪

      ZFCopy(f,t);
    //    ZJCopy(f,t);

    }

    private static void ZFCopy(String f, String t) {
        //1.定义再整个方法中都生效的局部变量,手动初始化值为null
        InputStream in = null;
        OutputStream out = null;
        //2.由于代码可能会发生异常,所以需要try-catch -finally 结构
        try{
            //3.创建高效/缓冲字节输入流,参数是f
            in =new BufferedInputStream(new FileInputStream(f));
            //3.2 创建高效/缓冲字节输出流 , 参数是t
            out = new BufferedOutputStream(new FileOutputStream(t));
            //4 创建好流对象以后就可以通过流对象完成业务了
            //4.1 定义变量保存读到的数据
            int b;
            while((b = in.read()) != -1){
                out.write(b);
            }
            System.out.println("恭喜您,文件复制成功");

        }catch (Exception e){
            System.out.println("很抱歉,文件复制失败");
            e.printStackTrace();
        }finally {
            //5.关流
            try {
                out.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
            try {
                in.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    private static void ZJCopy(String f, String t) {

        Writer out = null;
        Reader in = null;
        try{
            //3.创建高效/缓冲字符输出流,输入的参数是源文件的路径
            in = new BufferedReader(new FileReader(f));
            //3.2 创建高效/缓冲字符输出流,传入的参数是目标文件的路径
            out = new BufferedWriter(new FileWriter(t));

            //4.拿到流对象以后,就可以使用流对象来完成业务了
            //4.1 定义变量用来记录读到的数据
            int b;
            //4.2 循环读取目标文件,知道返回值为-1,没有数据时结束循环
            while(( b = in.read()) != -1){
                out.write(b);//将本次循环从源文件读到的内容写出到目标文件中
            }
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            /**
             * 关流是有顺序的: 如果有多个流,最后创建的流最先关闭
             * 多条关流语句需要各自try - catch
             */
            try {
                out.close();
               // in.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
            try {
                in.close();
            } catch (IOException e) {
                e.printStackTrace();
            }

        }
    }
}
package cn.tedu.generic;

import java.util.ArrayList;
import java.util.List;

/**
 * 本类用于测试泛型的好处1
 * @author ZHU
 * @create 17/08/2021 16:41
 */
public class TestGeneric {
    public static void main(String[] args) {
        //1.定义一个String类型,长度为5的数组
        String[] a = new String[5];
        a[2] = "paopao";
        a[4] = "xiaxia";
        //数组的好处: 在编译时期检查数据的类型,如果不是要求的类型会在编译期就报错
        /**
         * 1.泛型是怎么来的??  -- 想要模拟数组的数据类型检查
         * 2.泛型通常结合着集合一起使用
         */
        //没有泛型,数据类型根本没有约束
        List list = new ArrayList<>();
        list.add("taotao");
        list.add(1);
        list.add(7.7);
        list.add('a');
        System.out.println(list);
        /**
         * 引入泛型
         * 主要目的是检查约束集合中元素的类型
         */
        /**
         * 泛型的好处: 可以把报错的时机提前,在编译期就博报错,而不是运行后才抛出错误
         * 在向集合中添加元素时,会先检查元素的数据类型,如果不是要求的数据类型就编译失败
         */
        List<String> list2 = new ArrayList<>();
        list2.add("leishen"); // 约束了集合类型以后,只可以传String类型的参数
        //list2.add(1)
        /**
         * <type> --type 的值必须是引用类型,不能使用基本类型
         * 至于使用什么引用类型,取决于自己的业务
         */
        List<Integer> list3 = new ArrayList<>();
    }
}
package cn.tedu.generic;

/**
 * 本类用于测试泛型的优点2
 * @author ZHU
 * @create 17/08/2021 17:17
 */
public class TestGeneric2 {
    public static void main(String[] args) {
        Integer[]  a =  {1,2,3,4,5,6,7,8,9,10};
        print(a);
        String[] b = {"f","saf","sdf","sf","jsdflkp","slkfjf","lsjdgi","klasdf"};
        print(b);
        Double[] c = {6.0, 6.6,6.66,6.666};
        print(c);

    }

    /**
     * 1.泛型可以实现通用代码的编写,使用E表示元素的类型element类型
     * 泛型的语法要求: 如果在使用方法上使用泛型, 必须两处同时出现
     * 一个是方法传入参数的类型是泛型,一个是返回值前加泛型<E>
     * @param cE
     */

    private static <E>void print(E[] c) {
        for ( E d :
                c) {
            System.out.println(d);
        }
    }

   /* private static void print(String[] b) {
        for (String s :
                b) {
            System.out.println(s);
        }
    }

    private static void print(Integer[] a) {*/
     /*   for (int i = 0; i < a.length; i++) {
            System.out.println(a[i]);
        }*/

        //2.使用高效/增强for循环来遍历数组中的元素
        /**
         * 高效for循环:
         * 格式: for(2 3 : 1) {循环体} 1 要遍历的数据 2 每轮要遍历到的数据类型 3. 变量的名字
         * 好处: 比普通for循环写法简单,效率高
         * 坏处: 没有办法想普通for循环那样根据下标来操作值,只能从头到尾依次遍历
         */
 /*       for (Integer i:
             a) {
            System.out.println(i);
        }
    }*/
}
package cn.tedu.review;

import java.io.*;

/**
 * 本类用于复习IO流对象的创建
 * @author ZHU
 * @create 17/08/2021 09:05
 */
public class TestIOCreate {
    public static void main(String[] args) {
        /*字节输入流*/
        //InputStream
        try {
            FileInputStream in = new FileInputStream(new File(""));
            FileInputStream in2 = new FileInputStream("");
            BufferedInputStream in3 = new BufferedInputStream(new FileInputStream(new File("")));
            BufferedInputStream in4 = new BufferedInputStream(new FileInputStream(""));

        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }
        /*字节输出流*/
        //OutputStream
        try {
            FileOutputStream out = new FileOutputStream("");
            FileOutputStream out2 = new FileOutputStream("",true);
            FileOutputStream out3 = new FileOutputStream(new File(""));
            FileOutputStream out4 = new FileOutputStream(new File(""),true);

            //这个位置传上述4个中任意一个FOS对象都可以
            BufferedOutputStream out5 = new BufferedOutputStream(new FileOutputStream(""));
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }

        /*字符输入流*/
        //Reader
        try {
            FileReader in5 = new FileReader("");
            FileReader in6 = new FileReader(new File(""));

            BufferedReader in7 = new BufferedReader(new FileReader(""));
            BufferedReader in8 = new BufferedReader((new FileReader(new File(""))));
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }
        /*字符输出流*/
        //Writer

        try {
            FileWriter out6 = new FileWriter(String.valueOf(new FileOutputStream(new File(""))));
            FileWriter out7 = new FileWriter("");
            FileWriter out8 = new FileWriter(new File(""));
            FileWriter out9 = new FileWriter(new File(""),true);

            BufferedWriter out10 = new BufferedWriter(new FileWriter(""));
            BufferedWriter out11 = new BufferedWriter(new FileWriter("",true));
            BufferedWriter out12 = new BufferedWriter(new FileWriter(new File("")));
            BufferedWriter out13 = new BufferedWriter(new FileWriter(new File(""),true));
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
package cn.tedu.serializable;

import java.io.Serializable;

/**
 *
 * @author ZHU
 * @create 17/08/2021 11:43
 */
public class Student implements Serializable {
    /**
     * 每次反序列化时,会拿着之前序列化生成的UID作比较
     * 只有两个UID一致时才能反序列化成功,否则报错
     * 解决方案1: 一次序列化操作对应一次反序列化操作
     * 解决方案2: 将UID写死,无论怎么修改Student类,UID都不变
     *
     */
    //1.创建学生类的属性
            //private static final long serializableUID =1
    private String name;
    private int age;
    private String addr;
    private char gender;
    //private char gender1;
    //private char gender2;

    public Student() {
        System.out.println("我是Student的无参构造");
    }

    //4.添加重写的方法toString(),想查看对象的属性值而不是地址值



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

    public Student(String name, int age, String addr, char gender) {
        this.name = name;
        this.age = age;
        this.addr = addr;
        this.gender = gender;
    }

    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 getAddr() {
        return addr;
    }

    public void setAddr(String addr) {
        this.addr = addr;
    }

    public char getGender() {
        return gender;
    }

    public void setGender(char gender) {
        this.gender = gender;
    }
}
package cn.tedu.serializable;

import java.io.*;

/**
 * 本类用于测试序列化与反序列化
 * 序列化: 是指把程序中的java对象永久保存在磁盘中,比如文件
 * 相当于是写出的过程,方向是out,用到的流是ObjectOutputStream
 * 反序列化: 是指把已经序列化在文件中保存的数据,读取/恢复成java对象的过程
 * 相当于是读取的过程,方向是in,用到的流是ObjectInputStream反序列化流
 *
 * 如果一个类的对象想要被序列化输出,那么这个类必须安装序列化接口,否则会报错
 * java.io.NotSerializableException: cn.tedu.serializable.Student
 * 	at java.io.ObjectOutputStream.writeObject0
 *
 * 	Serializable 接口是一个空接口,里面一个方法都没有
 * 	作用是当做标志,标志这个类可以被序列化
 * @author ZHU
 * @create 17/08/2021 11:53
 */
public class TestSerializable {
    public static void main(String[] args) {
        method1();
        methed2();

    }

    /**
     * 反序列化方法
     */
    private static void methed2() {
        //1.声明一个在本方法内都生效的局部标量,手动初始化值为null
        ObjectInputStream in = null;
        //2.由于IO流操作可能会产生异常,所以需要使用try-catch-finally结构
        try{
            in = new ObjectInputStream(new FileInputStream(new File("D:\\TestFile\\1.txt")));
            //4.通过OIS反序列化流对象来读取恢复对象
            Object o = in.readObject();
            System.out.println(o);
            System.out.println("恭喜您!  反序列化成功");
        }catch (Exception e){
            System.out.println("很抱歉!, 反序列化失败");
            e.printStackTrace();
        }finally {
            try {
                in.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

    }

    /**
     * 序列化
     */
    private static void method1() {
        //1.声明一个在本方法中都生效的局部变量,手动初始化值为null
        ObjectOutputStream out = null;
        //2.由于IO操作可能会发生异常,所以使用try - catch - finally
        try{
            out = new ObjectOutputStream(new FileOutputStream("D:\\TestFile\\1.txt"));
            //4.指定一个要序列化输出的对象
            Student obj = new Student("likui",16,"liushuxia",'男');
            //5.使用oos流将对象输出
            out.writeObject(obj);
            System.out.println("恭喜您,序列化成功");
        }catch(Exception e){
            System.out.println("很抱歉,序列化失败");
            e.printStackTrace();
        }finally{
            //6.关流
            try {
                out.close();
            } catch (IOException e) {
                e.printStackTrace();
            }

        }
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值