40

我偶然发现了理解 java 序列化。我在许多文档和书籍中读到静态和瞬态变量不能在 Java 中序列化。我们声明一个 serialVersionUid 如下。

private static final long serialVersionUID = 1L;

如果静态变量没有被序列化,那么我们在反序列化过程中经常会遇到异常。

java.io.InvalidClassException

其中从反序列化对象中提取serialVersionUID,并与加载类的serialVersionUID进行比较。

据我所知,我认为如果静态变量不能被序列化。这个例外没有任何意义。我可能错了,因为我还在学习。

“java中的静态和瞬态变量不能被序列化”是一个神话吗?请纠正我,我对这个概念一团糟。

4

9 回答 9

69
  1. 实例变量:这些变量是序列化的,所以在反序列化过程中我们会取回序列化状态。

  2. 静态变量:这些变量没有序列化,所以在反序列化过程中,静态变量值将从类中加载。(当前值将被加载。)

  3. 瞬态变量: transient变量未序列化,因此在反序列化期间,这些变量将使用相应的默认值进行初始化(例如:对于对象nullint 0)。

  4. 超类变量:如果超类也实现了 Serializable 接口,那么这些变量将被序列化,否则不会序列化超类变量。并且在反序列化时,JVM 将在超类中运行默认构造函数并填充默认值。所有超类都会发生同样的事情。

于 2013-05-10T07:43:56.900 回答
54

serialVersionUID 是序列化和反序列化过程使用的特殊静态变量,用于验证本地类是否与用于序列化对象的类兼容。它不仅仅是一个静态变量,它绝对不是序列化的。

当一个类的对象第一次被序列化时,一个包含类名和序列版本 UID 的类描述符被写入流中。当它被反序列化时,JVM 检查从流中读取的序列版本 UID 是否与本地类的 UID 相同。如果不是,它甚至不会尝试反序列化对象,因为它知道类不兼容。

于 2012-06-12T16:45:36.863 回答
5

serialVersionUID是特殊的,不受这些规则的约束。序列化机制中有专门处理此字段以执行自动版本检查的代码。

于 2012-06-12T16:44:01.680 回答
2

您可以自己测试一下 - 这里有一些示例代码可以回答您的问题:

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;

class TestJava implements Serializable{
  public static int k = 10;
  public int j = 5;

  public static void main(String[] args) {

    TestJava tj1= new TestJava();
    TestJava tj2;

        try{ //serialization
            FileOutputStream fos = new FileOutputStream("myclass.ser");
            ObjectOutputStream oos = new ObjectOutputStream(fos);
            oos.writeObject(tj1);
            oos.close();
            fos.close();
            System.out.println("object serielized 1..."+tj1.j);
            System.out.println("object serielized 2..."+tj1.k);
            System.out.println("object serielized 3..."+k);
            k=++k; // 'k' value incrementd after serialization
          } catch(FileNotFoundException fnfe){
             fnfe.printStackTrace();
          } catch(IOException ioex){
             ioex.printStackTrace();
          }

          try{ //deserialization
              FileInputStream fis = new FileInputStream("myclass.ser");
              ObjectInputStream ois = new ObjectInputStream(fis);
              tj2 = (TestJava) ois.readObject();
              ois.close();
              fis.close();
              System.out.println("object DEEEEserielized 1..."+tj2.j);
              System.out.println("object DEEEEserielized 2..."+tj2.k); 
              System.out.println("object DEEEEserielized 3..."+k); 
            // in deserialization 'k' value is shown as incremented. 
            // That means Static varialbe 'K' is not serialized.
            // if 'K' value is serialized then, it has to show old value before incrementd the 'K' value.
            } catch(FileNotFoundException fnfe){
              fnfe.printStackTrace();
            } catch(IOException ioex){
              ioex.printStackTrace();
            } catch(ClassNotFoundException CNFE){
              CNFE.printStackTrace();                   
           }
      }
}

这将输出以下内容:

object serielized 1...5
object serielized 2...10
object serielized 3...10
object DEEEEserielized 1...5
object DEEEEserielized 2...11
object DEEEEserielized 3...11

因此,我们创建了一个TestJava具有一个静态整数字段和一个非静态字段的类对象。我们序列化对象,然后 - 在序列化之后 - 增加静态整数。

当我们稍后反序列化该对象时,我们看到它具有递增的值,这意味着它没有被序列化。

于 2015-02-01T17:15:48.947 回答
1

在这种serialVersionUID情况下也是序列化的。

在类初始化期间提供值的任何静态变量都会被序列化

但是,在正常情况下,您将在主类/运行时向静态变量提供值的位置不会被序列化。

您可以尝试serialVersionUID通过将其公开来访问它,并在反序列化后尝试访问它。

您可以参考“ http://javabeginnerstutorial.com/core-java-tutorial/transient-vs-static-variable-java/ ”了解更多信息。

希望有帮助。干杯!!

于 2017-02-26T12:55:27.050 回答
0

下面的示例解释了静态、实例、瞬态和超类变量序列化及其输出。

序列化类:

public class SerializeEx extends SuperSerializeEx implements Serializable {

    private static final long serialVersionUID = 1L;
    public static int staticNumber = 1234;
    public int instanceNumber = 1234;

    public SerializeEx() {
        staticNumber = 0;
        instanceNumber = 0;
        System.out.println("---sub class constructor---");
    }

    public SerializeEx(int staticNumber, int instanceNumber, int superNumber) {
        super(superNumber);
        this.staticNumber = staticNumber;
        this.instanceNumber = instanceNumber;
    }
}

超级班:

public class SuperSerializeEx {

    public int superNumber;

    public SuperSerializeEx() {
        System.out.println("---super class constructor---");
        this.superNumber = 1000;
    }

    public SuperSerializeEx(int superNumber) {
        this.superNumber = superNumber;
    }
}

序列化和反序列化:

public class MainSerialization {

    public static void main(String[] args) {
        String fileName = "testing.txt";
        serialize(fileName);
        deSerialize(fileName);
    }

    public static void serialize(String fileName) {
        System.err.println("Serialize.....");
        SerializeEx serializeMe = new SerializeEx(10, 10, 10);
        FileOutputStream fos = null;
        ObjectOutputStream out = null;
        try {
            fos = new FileOutputStream(fileName);
            out = new ObjectOutputStream(fos);
            out.writeObject(serializeMe);
            out.close();
        } catch (IOException ex) {
            ex.printStackTrace();
        }
    }

    public static void deSerialize(String fileName) {
        System.err.println("DeSerialize.....");
        SerializeEx time = null;
        FileInputStream fis = null;
        ObjectInputStream in = null;
        try {
            fis = new FileInputStream(fileName);
            in = new ObjectInputStream(fis);
            time = (SerializeEx) in.readObject();
            in.close();
        } catch (IOException ex) {
            ex.printStackTrace();
        } catch (ClassNotFoundException ex) {
            ex.printStackTrace();
        }
        System.err.println("Instance Numer = " + time.instanceNumber + " \tStatic Number= " + time.staticNumber + " \t Super Number= " + time.superNumber);
        SerializeEx serializeMe = new SerializeEx(1001, 1001, 1001); //Modifying the static and instnce variables
        System.err.println("Instance Numer = " + time.instanceNumber + " \tStatic Number= " + time.staticNumber + " \t Super Number= " + time.superNumber);
    }
}

输出:

---super class constructor---
Serialize.....
DeSerialize.....
Instance Numer = 10     Static Number= 10      Super Number= 1000
Instance Numer = 10     Static Number= 1001    Super Number= 1000
于 2013-05-10T07:54:02.533 回答
0

不,如果一个类有静态变量,那么在序列化时该变量将被跳过。因为静态变量对所有对象都是唯一的,并且序列化仅用于保存对象属性(对象状态)。静态变量是类的属性

于 2017-11-07T11:47:59.037 回答
0

的,如果在声明时初始化静态变量,它将被序列化。

例如,

案例1:声明时没有初始化

class Person implements Serializable{

  public String firstName;

  static  String lastName;  
}

public class Employee {

  public static void main(String[] args) {

      Person p = new Person();
      p.firstName="abc";
      p.lastName="xyz";
      //to do serialization

  }

}

输出 :

//after deserialization

 firstName= abc

 lastName= null

案例2:声明时初始化

class Person implements Serializable{

  public String firstName=="abc";

  static  String lastName="pqr";  
}

public class Employee {

  public static void main(String[] args) {

      Person p = new Person();
      p.firstName="abc";
      p.lastName="xyz";
      //to do serialization

  }

 }

输出 :

//反序列化后

firstName= abc

lastName= pqr
于 2018-07-11T12:34:57.813 回答
0

在声明时已初始化的任何静态变量都将被序列化。

于 2019-06-23T17:15:39.320 回答