【搞定Java基础】Java中的序列化和反序列化

 

结合自http://swiftlet.net/archives/1268https://baijiahao.baidu.com/s?id=1622011683975285944&wfr=spider&for=pc

众所周知,类的对象会随着程序的终止而被垃圾收集器销毁。如果要在不重新创建对象的情况下调用该类,该怎么做?这就可以通过序列化将数据转换为字节流。

对象序列化是一个用于将对象状态转换为字节流的过程,可以将其保存到磁盘文件中或通过网络发送到任何其他程序

从字节流创建对象的相反的过程称为反序列化。而创建的字节流是与平台无关的,在一个平台上序列化的对象可以在不同的平台上反序列化。

1、如何使Java类可序列化?

通过实现java.io.Serializable接口,可以在Java类中启用可序列化。它是一个标记接口,意味着它不包含任何方法或字段,仅用于标识可序列化的语义

2、如果我们试图序列化不可序列化的对象怎么办?

我们将得到一个 RuntimeException 异常:主线程中出现异常 java.io.NotSerializableException。

3、什么是serialVersionUID?

SerialVersionUID是一个标识符,当它通常使用对象的哈希码序列化时会标记在对象上。我们可以通过Java中serialver工具找到该对象的serialVersionUID。

语法:serialver classname,SerialVersionUID用于对象的版本控制。当您添加或修改类中的任何字段时,已经序列化的类将无法恢复,因为serialVersionUID已为新类生成与旧的序列化对象将不同。Java序列化过程依赖于正确的serialVersionUID恢复序列化对象的状态,并在serialVersionUID不匹配时抛出java.io.InvalidClassException 异常。

4、Transient 关键字

transient修饰符仅适用于变量,不适用于方法和类。在序列化时,如果我们不想序列化特定变量以满足安全约束,那么我们应该将该变量声明为transient。执行序列化时,JVM会忽略transient变量的原始值并将默认值保存到文件中。因此,transient意味着不要序列化。

5、Transient 与 Static

静态变量不 是对象状态的一部分,因此它不参与序列化。所以将静态变量声明为transient变量是没有用处的。

6、Final 与 Transient

final变量将直接通过值参与序列化,所以将final变量声明为transient变量不会产生任何影响。

7、serialVersionUID作用:如果我们不希望通过编译来强制划分软件版本,即实现序列化接口的实体能够兼容先前版本,就需要显式地定义一个名为serialVersionUID,类型为long的变量,不修改这个变量值的序列化实体都可以相互进行串行化和反串行化。

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

serialVersionUID有两种显式的生成方式:        

一是默认的1L,比如:private static final long serialVersionUID = 1L;        

二是根据类名、接口名、成员方法及属性等来生成一个64位的哈希字段,比如:        
private static final  long   serialVersionUID = xxxxL;

当实现java.io.Serializable接口的类没有显式地定义一个serialVersionUID变量时候,Java序列化机制会根据编译的Class自动生成一个serialVersionUID作序列化版本比较用,这种情况下,如果Class文件(类名,方法明等)没有发生变化(增加空格,换行,增加注释等等),就算再编译多次,serialVersionUID也不会变化的。如果发生改变,则会变化。

  • 情况一:假设Person类序列化之后,从A端传输到B端,然后在B端进行反序列化。在序列化Person和反序列化Person的时候,A端和B端都需要存在一个相同的类。如果两处的serialVersionUID不一致,会产生Exception in thread "main" java.io.InvalidClassException:错误
  • 情况二:假设两处serialVersionUID一致,如果A端增加一个字段,然后序列化,而B端不变,然后反序列化,会是什么情况呢?

【答案】新增 public int age; 执行SerialTest,生成序列化文件,代表A端。删除 public int age,反序列化,代表B端,最后的结果为:执行序列化,反序列化正常,但是A端增加的字段丢失(被B端忽略)。

  • 情况三:假设两处serialVersionUID一致,如果B端减少一个字段,A端不变,会是什么情况呢?

【答案】序列化,反序列化正常,B端字段少于A端,A端多的字段值丢失(被B端忽略)。

  • 情况四:假设两处serialVersionUID一致,如果B端增加一个字段,A端不变,会是什么情况呢?

【答案】序列化,反序列化正常,B端新增加的int字段被赋予了默认值0。

Employee类:

package test.SerialTest;

import java.io.Serializable;

public class Employee implements Serializable {
    private static final long serialVersionUID = 1L;
    private String name;
    private transient int salary;
    private int add;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getSalary() {
        return salary;
    }

    public void setSalary(int salary) {
        this.salary = salary;
    }

    @Override
    public String toString(){
        return "name = " +name+" ; salary = "+salary;
    }

}

序列化测试类:

package test.SerialTest;

import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;

public class Serialize {
    public static void main(String[] args) {
        Employee e  = new Employee();
        e.setName("zhaojing");
        e.setSalary(15);

        try {
            ObjectOutputStream ss = new ObjectOutputStream(new FileOutputStream("employeeTest"));
            ss.writeObject(e);
            ss.close();
        }catch (IOException ex){
            ex.printStackTrace();
        }

    }
}

反序列化测试类

package test.SerialTest;

import java.io.FileInputStream;
import java.io.IOException;
import java.io.ObjectInputStream;

public class ReverseSerialize {
    public static void main(String[] args) {
        try {
            ObjectInputStream in = new ObjectInputStream(new FileInputStream("employeeTest"));
            Employee employee = (Employee)in.readObject();
            in.close();
            System.out.println(employee);
        }catch (IOException | ClassNotFoundException e){
            e.printStackTrace();
        }

    }
}
### JSON序列化反序列化的概念 JSON(JavaScript Object Notation)是一种轻量级的数据交换格式,易于人类阅读编写,同时也便于机器解析生成。JSON序列化是指将对象或数据结构转换为JSON字符串的过程;而JSON反序列化则是指将JSON字符串还原成对象或数据结构的操作。 --- ### 使用Java中的Jackson库进行JSON序列化反序列化Java中,可以通过`ObjectMapper`类完成JSON的序列化反序列化操作。以下是具体实现方法: #### 序列化 通过调用`ObjectMapper`实例的方法`writeValueAsString()`可将Java对象转化为JSON字符串。 ```java import com.fasterxml.jackson.databind.ObjectMapper; public class JsonSerializationExample { public static void main(String[] args) throws Exception { ObjectMapper objectMapper = new ObjectMapper(); MyData myData = new MyData("example", 123); String jsonString = objectMapper.writeValueAsString(myData); // 将对象转为JSON字符串 System.out.println(jsonString); } } class MyData { private String name; private int value; public MyData(String name, int value) { this.name = name; this.value = value; } // Getters and Setters (required by Jackson) } ``` 此过程展示了如何利用Jackson库将自定义对象`MyData`序列化为JSON字符串[^1]。 #### 反序列化 通过调用`readValue()`方法可以从JSON字符串恢复到对应的Java对象。 ```java import com.fasterxml.jackson.databind.ObjectMapper; public class JsonDeserializationExample { public static void main(String[] args) throws Exception { ObjectMapper objectMapper = new ObjectMapper(); String jsonString = "{\"name\":\"example\",\"value\":123}"; MyData myData = objectMapper.readValue(jsonString, MyData.class); // 将JSON字符串转回对象 System.out.println(myData.getName()); } } ``` 上述代码片段说明了如何使用Jackson库执行反序列化操作。 --- ### 在Spring Boot环境中使用`ObjectMapper` 对于基于Spring Boot的应用程序,可以直接注入并配置`ObjectMapper`用于更复杂的场景,比如处理日期格式或者嵌套的对象结构。 ```java @SpringBootApplication public class Application { @Bean public ObjectMapper objectMapper() { ObjectMapper mapper = new ObjectMapper(); mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); return mapper; } public static void main(String[] args) { SpringApplication.run(Application.class, args); } } ``` 这段代码展示了一个简单的Spring Boot应用程序初始化带有特定配置项的`ObjectMapper`实例的方式[^2]。 --- ### C#中的JSON序列化反序列化 除了Java,在C#中也可以借助`.NET Framework`自带的功能来进行类似的处理。例如,可以采用`System.Web.Script.Serialization.JavaScriptSerializer`类来达成目标。 ```csharp using System.Web.Script.Serialization; public class Program { public static void Main(string[] args){ JavaScriptSerializer serializer = new JavaScriptSerializer(); var obj = new { Name="Test", Value=42 }; string jsonStr = serializer.Serialize(obj); dynamic deserializedObj = serializer.Deserialize<object>(jsonStr); } } ``` 这里提供了关于怎样运用C#里的工具去管理JSON资料的一个例子[^3]。 --- ### 原生JavaScript中的JSON序列化反序列化 如果是在浏览器端或者是Node.js环境下工作,则不需要额外引入任何第三方库即可轻松搞定这些需求。 - **序列化**: `JSON.stringify(object)` - **反序列化**: `JSON.parse(string)` 或者 `eval('('+string+')')`, 不过推荐前者因为安全性更高一些[^4]. ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值