【问题标题】:Are static variables serialized in Serialization process静态变量是否在序列化过程中序列化
【发布时间】:2012-06-15 14:09:40
【问题描述】:

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

private static final long serialVersionUID = 1L;

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

java.io.InvalidClassException

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

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

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

【问题讨论】:

    标签: java


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

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

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

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

    【讨论】:

    • "所以在反序列化的同时,静态变量值将从类中加载。(当前值将被加载。)" 如果类在不同的 JVM 中被反序列化怎么办?
    • @mdev:正确的说法是static 变量根本没有被触及。说“静态变量值将从类中加载”是没有意义的——加载到自身中。
    【解决方案2】:

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

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

    【讨论】:

    • 特殊静态变量是什么意思?
    • 表示它是一个特殊的静态变量。 (具体来说,它与序列化中的其他静态变量的处理方式不同。)
    • 比较特别,因为序列化机制通过查找这个静态变量来知道类的序列版本UID是什么。序列化机制会忽略所有其他静态变量。
    • 感谢您的准确回答,不胜感激。
    • 静态变量属于一个类而不属于任何单个实例。序列化的概念与对象的当前状态有关。只有与类的特定实例关联的数据才会被序列化,因此在序列化过程中会忽略静态成员字段。
    【解决方案3】:

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

    【讨论】:

      【解决方案4】:

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

      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 的对象,其中包含一个静态整数字段和一个非静态字段。我们序列化对象,然后 - 在序列化之后 - 增加静态整数。

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

      【讨论】:

      • 谢谢。 static variables 没有被序列化,无论它们在哪里初始化。
      【解决方案5】:

      serialVersionUID 在这种情况下也被序列化了。

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

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

      您可以尝试通过将serialVersionUID设为public来访问它,并在反序列化后尝试访问它。

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

      希望对您有所帮助。干杯!!

      【讨论】:

      • No 静态变量被序列化,无论它是否在类初始化期间提供了值。您引用的来源和您的答案都不正确,并且您的引用明显自相矛盾。
      【解决方案6】:

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

      序列化类:

      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
      

      【讨论】:

      • 例子说明什么。他们只是表现出行为。
      【解决方案7】:

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

      【讨论】:

        【解决方案8】:

        是的,静态变量如果在声明的时候被初始化就会被序列化。

        例如,

        案例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
        

        【讨论】:

          【解决方案9】:

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

          【讨论】:

            猜你喜欢
            • 2012-10-31
            • 2015-01-13
            • 2018-08-08
            • 1970-01-01
            • 2016-03-24
            • 1970-01-01
            • 1970-01-01
            • 2020-06-07
            • 1970-01-01
            相关资源
            最近更新 更多