Java 无法从.dat文件读取可序列化类

Java 无法从.dat文件读取可序列化类,java,objectoutputstream,objectinputstream,Java,Objectoutputstream,Objectinputstream,我尝试编写一个密钥持有者,我想使用ObjectOutputStream将密码写入.dat文件,然后使用ObjectInputStream读取密码。这是我编写对象的代码: public void toFile() { try { ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("passwords.dat")); for(int i = 0;

我尝试编写一个密钥持有者,我想使用ObjectOutputStream将密码写入.dat文件,然后使用ObjectInputStream读取密码。这是我编写对象的代码:

public void toFile()
{    
    try
    {
        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("passwords.dat"));     
        for(int i = 0; i<this.nrOfPW; i++)
        {
            if(this.PWlist[i] instanceof longPW)
            {
                oos.writeObject((longPW)this.PWlist[i]);
            }
            else
            {
                oos.writeObject((PinPW)this.PWlist[i]);
            }   
        }
        oos.close();
    }
    catch(IOException e)
    {
        e.getStackTrace();
    }
}
PWlist数组是一个Info数组,PinPW和longPW扩展了Info

如何解决此问题?

让我们先解决“第一个bug,第一个”

在此代码中:

while(objIn.readObject() != null)                         // reads object, tests then *discards* it
{
  ...

  if(objIn.readObject() instanceof PinPW)                 // reads object, tests then *discards* it
  {
    this.PWlist[this.nrOfPW] = (PinPW)objIn.readObject(); // conditionally read an object
    this.nrOfPW++;
  }
  else
  {
    this.PWlist[this.nrOfPW] = (longPW)objIn.readObject(); // conditionally read an object
    this.nrOfPW++;
  }
}
每次循环迭代时,实际上都会读取3个对象。第一次读取对象以检查流中是否存在对象时,下一次读取对象并确定其类型时,将其丢弃。然后读取第三个对象,并根据丢弃对象的类型对其进行强制转换

此外,正如正确指出的,确定ObjectInputStream流结束的正确方法是捕获文件结束异常

您要改为执行此操作:

 try
 {
   while (true)
   {
     final Object o = objIn.readObject();            // read the object from the stream

     ...

     if (o instanceof PinPW)
     {
       this.PWlist[this.nrOfPW] = (PinPW) o;         // cast to correct type
       this.nrOfPW++;
     }
     else
     {
       this.PWlist[this.nrOfPW] = (longPW) o;        // cast to correct type
       this.nrOfPW++;
     }
   }
 }
 catch (EOFException e)
 {
   // end of stream reached ...
   // ... close the file descriptor etc ...
 }

你这里有个问题

while(objIn.readObject() != null)
    {
        if(this.nrOfPW == this.PWlist.length)
        {
            expand(10);
        }
        if(objIn.readObject() instanceof PinPW)
        {
            this.PWlist[this.nrOfPW] = (PinPW)objIn.readObject();
            this.nrOfPW++;
        }
        else
        {
            this.PWlist[this.nrOfPW] = (longPW)objIn.readObject();
            this.nrOfPW++;
        }
    }
您正在多次阅读一个对象。尝试保存它,然后使用它。 如果(objIn.readObject()instanceof PinPW)读取一次,读取两次,则this.PWlist[this.nrOfPW]=(PinPW)objIn.readObject();读了三次,但应该只读一次。
PS:在一段时间内使用GregKopff语法,不使用final关键字,因为您希望在其中保存更多对象

我只想指出
toFile()
函数中的if-else块完全没有意义
writeObject()
接受对象参数。它不关心它是什么类型的对象,只要它是可序列化的

虽然您的
fromFile()
方法存在严重缺陷,但它不会导致
NotSerializableException
。我相信您提到的异常实际上发生在
toFile()


原因很简单:您没有完全阅读和理解的文档。具体来说,对象及其所有非瞬态字段及其祖先类中的所有非瞬态字段必须实现可序列化。它还必须有一个公共的无参数构造函数。

您能发布生成的异常和堆栈跟踪吗?请参阅我的答案,以了解此问题的可能修复方法,以及bug的明确修复方法。[主题外]按惯例,Java类是使用大写开始camelcase命名的——这意味着您的
longPW
类应该是
longPW
。类似地,变量的命名使用小写字母estartingcamelcase,因此您的
PWList
变量应被称为
PWList
。您可以简化创建文件的方法。调用
writeObject
时,您不需要检查对象的类型,也不需要强制转换它们,因为这里的参数是
object
。但是,您必须确保所有传递的对象都实现接口
java.io.Serializable
,因为这不是由编译器强制执行的(它是由序列化输出流强制执行的)。“它必须有一个公共的无参数构造函数”-这对于
可外部化的
类是正确的,但对于
可序列化的
类则不是,你是对的,这不是一个严格的要求,但我一直都有这些要求,因为如果没有这些要求的话,分类会很复杂。我不想费心去记住关于这个的所有规则,所以我只是这样统一它:)你在想:“为了允许不可序列化类的子类型被序列化,子类型可能负责保存和恢复超类型的public、protected和(如果可访问)的状态包字段。仅当子类型扩展的类具有可访问的无参数构造函数来初始化该类的状态时,该子类型才可以承担此责任。“@Psyberion根本没有理由测试null,除非您在序列化时写入null。序列化流上EOS的正确测试是捕获
EOFEException
while(objIn.readObject() != null)
    {
        if(this.nrOfPW == this.PWlist.length)
        {
            expand(10);
        }
        if(objIn.readObject() instanceof PinPW)
        {
            this.PWlist[this.nrOfPW] = (PinPW)objIn.readObject();
            this.nrOfPW++;
        }
        else
        {
            this.PWlist[this.nrOfPW] = (longPW)objIn.readObject();
            this.nrOfPW++;
        }
    }