【问题标题】:JAVA - Static variable resets upon program restartJAVA - 程序重新启动时静态变量重置
【发布时间】:2013-04-23 12:45:18
【问题描述】:

我对静态计数器变量有疑问。在一个超级类(“卡片”)中,我有一个变量来计算注册的卡片数量(这是一个票务系统)。是这样写的:

public class Card implements Serializable    {
    private int id;
    public static int nextNr= 000;
    Card next;

    public Card(int t)   {
        id= ++nextNr;
        next= null;
    }
}

该类实现 Serializable,我使用 ObjectStream 将卡片写入文件。

但是如果我关闭程序并重新启动它,它可以从文件中读取并确认并将文件再次添加到我的卡注册表中。但是,超级类中的卡计数器变量被重置,我尝试注册的每张新卡都再次从 001 开始。我究竟做错了什么? 似乎无法在网上找到有关此特定问题的任何信息。

解决方案: 我使用 DataOutputStream 在退出时保存它,并在启动时使用 DataInputStream 读取它。 我不知道这是否是最有效的方法,但它确实有效。非常感谢你们的cmets,它帮助了我很多!!!!

abstract public class Card implements Serializable  {

private int type;
private int cardNr;
private static int nextNr = readCardNr();
Card next;   //COllections or not.. hmmmm

public Card(int t)   {
    cardNr= ++nextNr;
    next= null;
    type = t;
    writeCardNr();
}

public int getType(){
    return type;
}

public void setCardNr(int i) {
    cardNr= i;
}
public int getCardNr()  {
    return cardNr;
}


public static int readCardNr() {        
    try(DataInputStream inn= new DataInputStream(new FileInputStream("KortNummer")))   {
        nextNr= inn.readInt();
        inn.close();
        return nextNr;
    }
    catch(FileNotFoundException fnfe)   {
        skrivMld("Fant ingen tidligere registrerte kort. Starter nytt kortregister.");
        nextNr= 000;
        return nextNr;
    }
    catch(EOFException eofe)    {
        System.out.println("End of file");
    }
    catch(IOException ioe)  {
        skrivMld("Feilmelding: IO Exception");
    }
    return nextNr;
}

public void writeCardNr()    {
    try(DataOutputStream ut= new DataOutputStream(new FileOutputStream("KortNummer"))){
        ut.writeInt(cardNr);
    }
    catch(IOException ioe)  {
        skrivMld("Problem med skriving til fil.");
    }
}

【问题讨论】:

标签: java static counter restart


【解决方案1】:

计数器是静态的。因此它不是任何卡片实例状态的一部分,序列化所有卡片不会保存计数器的值。

要么保存此计数器值,重新加载并显式重置它,要么在启动时从所有反序列化卡中获取最大 ID 并将计数器重置为此最大值。

【讨论】:

  • 谢谢!我在程序的出口写了卡id,一开始就读进去,果然成功了! =)
【解决方案2】:

序列化不会持久化静态变量的值。因此,当再次加载该类时,会设置默认值(静态整数为零)。要持久化该值,请将变量设为对象级别。

如果您仍想保留静态变量的值,则需要使用private void readObject(ObjectInputStream)private void writeObject(ObjectOutputStream) 提供自定义序列化

注意:用对象序列化静态变量(通过提供自定义序列化)可能会导致问题。

想一想这样的场景:您创建一个 Card 对象并将其序列化。静态计数器为1。您创建另一个卡片对象并将其序列化。静态计数器为2。因此,您创建了 10 个对象并序列化了每个对象。静态计数器为10。因此,除非您反序列化最后一个对象,否则您将无法获得正确的计数器值。

为了避免这个问题并仍然存储卡片的数量,您可以创建一个包装类Cards

public class Cards implements Serializable    {
    private List<Card> cardList = new ArrayList<Card>();
    // getter and setter

}

在开始时首先加载(反序列化)Cards 对象。每当您创建 Card 对象时,将其添加到 Cards (cardList) 并序列化 Cards 对象。

【讨论】:

  • 我不确定我是否理解关于序列化卡片和包装类的最后一点?我只是在程序退出时将数字存储在一个文件中,然后在程序启动时将其加载。
【解决方案3】:

静态成员没有被序列化。它们属于类,而不是正在序列化的类的实例。

【讨论】:

    【解决方案4】:

    static fields 仅在static 范围内one JVM 即如果您停止执行,他们将失去他们的scope and data.

    【讨论】:

      【解决方案5】:

      当程序关闭并重新启动时,静态不会保存/保留该值。 static 修饰符用作类级别变量,其值在任何新对象创建过程中都保持不变,并且这些对象也可以通过类级别访问该静态值。例如

      public class A{
      public static int val = 0;
      public int verify = 0;
      public A(){
      val++;
      }
      }
      
      A a = new A();      // val = 1
      A b = new A();      // val = 2
      A c = new A();      // val = 3
      
      a.verify = A.val;   // val = 3
      b.verify = A.val;   // val = 3
      c.verify = A.val;   // val = 3
      

      现在要保留该静态值,您应该将其保存到某个文件或数据库中,并在应用程序重新启动时,根据需要从那里初始化该静态值。

      【讨论】:

        【解决方案6】:

        根据 Java 规范,静态变量不是实例的一部分,而是类级别的一部分。当你序列化数据时,你只为 Object 而不是 Class,所以静态不会被持久化。

        当你重启类后重新加载类时,它会加载变量的默认值。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2014-11-22
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多