【问题标题】:Deserialized object fields are null反序列化的对象字段为空
【发布时间】:2017-01-10 23:20:05
【问题描述】:

我已经成功序列化了我的自定义对象,但是当我反序列化它时会发生这种情况:

-自定义对象不为空

-所有字段为NULL

我知道我已经成功序列化了我的自定义对象,因为我已经阅读了序列化文件并且它看起来很好。

这是我的代码:

public class Preferences implements Serializable {

private static Preferences instance;
public static final long serialVersionUID = 3358037972944864859L;
public String accessToken;

protected Object readResolve() {
    return getInstance();
}

private Preferences() {

}

private synchronized static void synchronize() {
    if(instance == null) {
        instance = new Preferences();
    }
}

public static Preferences getInstance() {
    if(instance == null) {
        Preferences.synchronize();
    }

    return instance;
}

public void save(File file) {
    try {
        FileOutputStream fos = new FileOutputStream(file);
        ObjectOutputStream out = new ObjectOutputStream(fos);

        Preferences tempInstance = Preferences.getInstance();

        out.writeObject(tempInstance);
        out.close();
        fos.close();
    }catch(IOException e) {
        e.printStackTrace();
    }
}

public void load(File file) {
    try {
        FileInputStream fis = new FileInputStream(file);
        ObjectInputStream in = new ObjectInputStream(fis);

        if(file.length() > 0) {
            Preferences tempInstance = (Preferences) in.readObject();

            Log.e("", String.valueOf(tempInstance == null)); //prints FALSE
            Log.e("", String.valueOf(tempInstance.accessToken == null)); //prints TRUE
        }

        in.close();
        fis.close();
    }catch(IOException | ClassNotFoundException e) {
        e.printStackTrace();
    }
}
}

这是我的测试代码:

public class CustomActivity extends AppCompatActivity {

private File dir = new File(Environment.getExternalStorageDirectory(), ".app");
private File backup = new File(dir, "backup.ser");

@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
    Log.e("APPLICATION", "START");

    super.onCreate(savedInstanceState);

    if(this instanceof ActivityLogin) {
        if(!dir.exists()) {
            dir.mkdirs();
        }

        Preferences.getInstance().load(backup);
    }
}

@Override
protected void onUserLeaveHint() {
    super.onUserLeaveHint();

    try {
        backup.createNewFile();
    } catch (IOException e) {
        e.printStackTrace();
    }

    Preferences.getInstance().save(backup);

    Log.e("APPLICATION", "STOP");
}

}

对可能出现的问题有任何想法吗?

【问题讨论】:

  • 你没有对读取的对象做任何事情。您的加载方法应该是静态的,并且应该返回反序列化的实例。 instancethis 是两个不同的、不相关的对象。
  • 在 load() 完成后,我正在对实例对象做一些事情,但在 load() 中,实例不为空,而其所有字段都为空。请看我的编辑。 @JBNizet
  • 发布一个完整的最小示例来重现错误。我们不知道您在序列化和反序列化什么。
  • @fabian 我已经解决了这个问题,但同样的问题。查看我的编辑。
  • @JBNizet 已发布完整代码。

标签: java android serialization


【解决方案1】:

你的课堂上有这个方法:

protected Object readResolve() {
    return getInstance();
}

这告诉了序列化机制:每当你反序列化一个 Preferences 实例时,用getInstance() 返回的那个替换它。所以,如果你调用 load() 并且你的 Preferences 实例有一个 null accessToken,那么反序列化的首选项也将有一个 null accessToken,因为它们是同一个对象。

添加

System.out.println(tempInstance == this);

到您的日志记录语句(或您在 android 中使用的任何日志记录),您会看到。

【讨论】:

  • 是的。但我也会停止使用糟糕的单例反模式。只需将 load 方法设为静态,使其返回反序列化的 Preferences,并将其存储在变量中即可。
  • 我已将加载方法设为静态并使其返回 Preferences 对象。如果我创建 setInstance() 来设置实例字段并将 load() 作为参数传递。
  • 我已经像上面所说的那样创建了 setInstance() 并遵循了您的建议,并且字段不为空。我还想学习一些单例模式/全局类的替代方法。非常感谢!
猜你喜欢
  • 1970-01-01
  • 2011-12-01
  • 2021-01-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-03-18
相关资源
最近更新 更多