Day111 Java基础知识点 序列化+拷贝

序列化

为什么:程序运行的过程中,所有变量都是在内存中操作的,当程序一旦执行完毕,结束退出后,变量占有的内存就被操作系统回收了。 因此我们需要将某些数据持久化存储到磁盘中,下次运行的时候从磁盘中读取相关数据。

是什么:我们将变量从内存中变成可以存储或传输的过程称之为序列化。

怎么用:对象的序列化主要有两种用途:(持久化+网络通信+RMI)

  1) 一是可以实现数据的持久化,把对象的字节序列永久地保存到硬盘上。

  2) 二是可以对象数据的远程通信,在网络上传送对象的字节序列。(比如转为Json数组)

       3)三是远程方法调用时(RMI,一种用于实现远程过程调用(RPC)的Java API)

代码实例:

package pac.IOstream;
import java.io.*;

/*
    ObjectOutputStream:对象的序列化流
    作用:把对象以流的方式写入到文件中保存

    使用步骤:
        1.创建ObjectOutputStream对象,构造方法中传递字节输出流
        2.使用ObjectOutputStream对象中的方法writeObject,把对象写入到文件中
        3.释放资源

    ObjectInputStream:对象的反序列化流
    作用:把文件中保存的对象,以流的方式读取出来使用

    使用步骤:
        1.创建ObjectInputStream对象,构造方法中传递字节输入流
        2.使用ObjectInputStream对象中的方法readObject读取保存对象的文件
        3.释放资源
        4.使用读取出来的对象(打印)

     readObject方法声明抛出了ClassNotFoundException(class文件找不到异常)
     当不存在对象的class文件时抛出此异常
     反序列化的前提:
        1.类必须实现Serializable
        2.必须存在类对应的class文件

     另外,当JVM反序列化对象时,能找到class文件,但是class文件在序列化对象之后发生了修改,
     那么反序列化操作也会失败,抛出一个`InvalidClassException`异常。
     Serializable` 接口给需要序列化的类,提供了一个序列版本号。`
     serialVersionUID` 该版本号的目的在于验证序列化的对象和对应类是否版本匹配。
 */

public class IOStream {
    public static void main(String[] args) {

        Employee employee = new Employee();
        employee.name = "王伟光";
        employee.address = "安阳市";
        employee.age = 24;
        employee.addressCheck();

        Employee employee1 = null;

        try {
            // 序列化
            ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("a.txt"));
            out.writeObject(employee);
            out.close();
            System.out.println("Serialized data is saved");
            // 反序列化
            ObjectInputStream in = new ObjectInputStream(new FileInputStream("a.txt"));
            employee1 = (Employee) in.readObject();
            in.close();

        } catch (IOException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            System.out.println("Employee class not found");
            e.printStackTrace();
        }
        // 无异常,直接打印输出
        System.out.println("Name: " + employee1.name);	// zhangsan
        System.out.println("Address: " + employee1.address); // beiqinglu
        System.out.println("age: " + employee1.age); // 0


    }
}

/*
    Serializable接口也叫标记型接口
        要进行序列化和反序列化的类必须实现Serializable接口,就会给类添加一个标记
            没有:就会抛出 NotSerializableException异常

    static关键字:静态关键字
        静态优先于非静态加载到内存中(静态优先于对象进入到内存中)
        被static修饰的成员变量不能被序列化的,序列化的都是对象

    transient关键字:瞬态关键字
        被transient修饰成员变量,不能被序列化
*/

class Employee implements java.io.Serializable {
    // 加入序列版本号
    private static final long serialVersionUID = 1L;
    public String name;
    public String address;
    public transient int age; // transient瞬态修饰成员,不会被序列化
    public void addressCheck() {
        System.out.println("Address  check : " + name + " -- " + address + "--" + age);
    }
}


不足:

1  无法跨语言

2  序列化后的码流太大

3 序列化性能太低

解决:无论是序列化后的码流大小,还是序列化的性能,JDK 默认的序列化机制表现都很差。因此,我们通常不会选择 Java 序列化作为远程跨节点调用的编解码框架。而是使用业界提供的很多优秀的编解码框架,它们在克服了 JDK 默认的序列化框架缺点的基础上,还增加了很多亮点。例如:Google 的 Protobuf、Facebook 的 Thrift 和 JBoss 的 Marshalling 等等

详细:https://blog.csdn.net/zhengzhaoyang122/article/details/100780222

 

拷贝

为什么:想对一个对象进行处理,又想保留原有的数据进行接下来的操作,就需要克隆了,Java语言中克隆针对的是类的实例。

是什么

  • 浅拷贝只是复制了对象的引用地址,两个对象指向同一个内存地址,所以修改其中任意的值,另一个值都会随之变化,这就是浅拷贝(Object1=Object2)

  • 深拷贝是将对象及值复制过来,两个对象修改其中任意的值另一个值不会改变,这就是深拷贝(例:重写Object.clone(),通过序列化和反序列化)

怎么用

深拷贝的两种方式:

1). 实现Cloneable接口并重写Object类中的clone()方法;

2). 实现Serializable接口,通过对象的序列化和反序列化实现克隆,可以实现真正的深度克隆。

比较:基于序列化和反序列化实现的克隆不仅仅是深度克隆,更重要的是通过泛型限定,可以检查出要克隆的对象是否支持序列化,这项检查是编译器完成的,不是在运行时抛出异常,这种是方案明显优于使用Object类的clone方法克隆对象。让问题在编译的时候暴露出来总是好过把问题留到运行时。

代码实例

package wangc.pac.clone;

public class ObjectClone {
    public static void main(String[] args) throws CloneNotSupportedException {
        //浅拷贝:值传递
        Person person1 = new Person("王c", 23);
        Person person1clone = person1;
        System.out.println(person1clone);
        System.out.println("person1==person1clone:" + (person1==person1clone));

        //深拷贝:clone方法
        // ① 实现Cloneable接口,这是一个标记接口
        //② 覆盖clone()方法,可见性提升为public
        Person person2 = new Person("李b", 18);
        Person person2clone = (Person) person2.clone();
        System.out.println(person2clone);
        System.out.println("person2==person2clone:" + (person2==person2clone));
    }
}

class Person implements Cloneable{
    String name;
    int age;

    public Person() {
    }

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

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

    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }
}

序列化实现。。。

https://blog.csdn.net/u012611620/article/details/81698596

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值