Java关键字transient和序列化问题

1. 问题描述

简述java中的transient关键字,并说说序列化。

2. 为了搞清楚transient,先从序列化说起。

  1. 什么是序列化?

Java中对象的序列化指的是将对象转换成以字节序列的形式来表示,这些字节序列包含了对象的数据和信息,一个序列化后的对象可以被写到数据库或文件中,也可用于网络传输。常需要让我们的实体类实现Serializable接口,目的就是为了让其可序列化。

  1. 什么是反序列化?

将原来的序列化对象恢复成原先的Java对象

  1. 我们在实现序列化注意的小问题
  • 我们序列化过程中需要实现Serializable接口,目的是为了持久化存储
  • JAVA序列化的机制是通过判断类的serialVersionUID来验证的版本一致的
  • serialVersionUID有两种方式生成。一种是private static final long serialVersionUID = 1L; 另一种是经过计算机系统时间,类名称等属性通过hash运算得到64位全球唯一的ID

3. 我们看一下具体代码实现

1. 定义一个矩形类,包含宽,高,面积属性

public class Rectangle implements Serializable {
    private static final long serialVersionUID = 5559700000000000001L;
    private Integer width;
    private Integer height;
    private Integer area;

    public Rectangle(Integer width, Integer height) {
        this.width = width;
        this.height = height;
        this.area = width * height;
    }

    public void setArea(Integer area) {
        this.area = this.width * this.height;
    }

    @Override
    public String toString() {
        StringBuffer sb = new StringBuffer(40);
        sb.append("width : ");
        sb.append(this.width);
        sb.append("\nheight : ");
        sb.append(this.height);
        sb.append("\narea : ");
        sb.append(this.area);
        return sb.toString();
    }
}

2. 序列化操作

// 我们会生成一个序列化文件
public class SerialTest {
    public static void main(String[] args) throws Exception {
        Rectangle rectangle = new Rectangle(3, 4);
        System.out.println("1.原始对象\n"+rectangle);
        ObjectOutputStream o = new ObjectOutputStream(
                new FileOutputStream("src/JobTest/rectangle.txt"));
        o.writeObject(rectangle);
        o.close();
    }
}

3. 反序列化操作

public class DeSerialization {
    public static void main(String[] args) throws Exception{
        ObjectInputStream in = new ObjectInputStream(
                new FileInputStream("src/JobTest/rectangle.txt"));
        Rectangle rectangle1 = (Rectangle) in.readObject();
        System.out.println("2.反序列化后的对象\n"+rectangle1);
    }
}

4. 思考及分析

1. 当序列化和反序列化serialVersionUID不相同时候,能否反序列化成功?
我们运行序列化代码后,修改serialVersionUID,再进行反序列化时候,报错如下:

Exception in thread "main" java.io.InvalidClassException: JobTest.Rectangle; 
local class incompatible: stream classdesc serialVersionUID = 5559700000000000000, 
local class serialVersionUID = 5559700000000000001

2. 当序列化serialVersionUID不变,且增加一个属性,反序列化是否会成功?
我们在矩形类文件上添加一个属性,然后进行反序列化,并不会报错,但是新增的属性没有值,被忽略。

3. 当序列化serialVersionUID不变,且减少一个属性,反序列化是否会成功?
我们在上一个矩形类文件减少一个属性并进行反序列化,并不会报错,但是减少的属性不会出现,被忽略。

5. 再研究transient关键字

transient关键字的作用,简单地说,就是让某些被修饰的成员属性变量不被序列化,在被反序列化后,transient 变量的值被设为初始值,如 int 型的是 0,对象型的是 null。

因此,我们依旧用上述代码进行测试,并在area前增加transient关键字,代码如下

private Integer width;
private Integer height;
private transient Integer area;

进行序列化结果如下:
在这里插入图片描述
进行反序列化结果如下:
在这里插入图片描述
另外,反序列化后的对象仍然可以调用对象里面的方法。

6. 参考文档连接

  1. https://blog.csdn.net/u014750606/article/details/80040130

  2. https://www.cnblogs.com/chenpi/p/6185773.html

  3. https://www.cnblogs.com/xuxinstyle/p/11394358.html

发布了103 篇原创文章 · 获赞 55 · 访问量 14万+

猜你喜欢

转载自blog.csdn.net/l8947943/article/details/104468282
今日推荐