为什么这个 Class' 对象在不同进程中没有正确序列化?

Why is this Class' object not serialized properly in different processes?

上下文

我制作了一个 Java 应用程序,需要 运行 该应用程序的两个实例,每次有一些变化时通过套接字同步它们的一些属性。为了传达这些变化,Serializable 对象使用 ObjectStreams(输入和输出)通过套接字发送,使用 read/writeUTF() 作为标识符,read/writeObject() 和 flush()。该应用程序是完全相同的 .jar,运行 两次,但有一些变化,例如具有不同的端口和 ip(如有必要)。

问题

我注意到我的一些 classes(例如 Notification)的对象发送和接收没有任何问题,但是来自另一个 class 的对象(RegisteredUsers ) 未正确发送(或接收)。所以我运行一些测试在两个应用程序之间发送对象,发现对象正在发送并且不为空,它的属性(HashMap<String,User>)也在发送并且不为空,但是 总是空的.
所以我决定将其缩小到问题的确切原因:我正在尝试通过 Stream 编写一个对象,并在同一个 .jar 的不同进程中读取它,并且大多数 classes 似乎可以工作,但没有一个。
关于这个序列化过程,我似乎遗漏了一些东西或者不理解,如果对象是在执行相同过程的过程中写入和读取的,那么它就可以工作,但如果这个对象是在同一个应用程序的另一个实例上读取的,则不会.我什至使用相同的创建过程向 Notification 添加了一个 HashMap,但它仍然有效,我真的不明白,我错过了什么?

代码

如果有人想测试的话,我已经从较大的应用程序中提取了一些代码并将其缩减为基本问题。要重现错误,运行 Main1 将创建两个文件,每个文件中都有一个对象(一个带有 Notification 对象,另一个带有 RegisteredUsers 对象)并显示它们的信息,然后 Main2 读取它们从文件中显示它们的信息,并且应该打印问题。那就是 reg3 的 HashMap 是空的,因此两个用户都没有注册。

主要 1

public class Main1 {
    
    public static void main(String[] args) {
        String regFile = "registry.txt";
        String notificationFile = "notification.txt";
        Persistence pers = new Persistence();
        
        RegisteredUsers reg1 = new RegisteredUsers();
        RegisteredUsers reg2 = new RegisteredUsers();
        
        reg1.register("Name1", "127.0.0.1");
        reg1.register("Name2", "127.0.0.1");
        
        try {
            pers.writeReg(reg1, regFile);
        } catch (IOException e) {
            System.out.println("Error writing registry.");
        }
        try {
            reg2 = pers.readReg(regFile);
        } catch (IOException e) {
            System.out.println("Error reading registry.");
        }
        System.out.println("Original registry: ");
        System.out.println(reg1.isRegistered("Name1") + " " + reg1.isRegistered("Name2"));
        System.out.println("Registry read from file: ");
        System.out.println(reg2.isRegistered("Name1") + " " + reg2.isRegistered("Name2"));
        
        Notification noti1 = new Notification("Name", "127.0.0.1");
        Notification noti2 = new Notification(); //not necesary but it's the way it's done in the bigger app.
        try {
            pers.writeNotif(noti1, notificationFile);
        } catch (IOException e) {
            System.out.println("Error writing notification.");
        }
        try {
            noti2 = pers.readNotif(notificationFile);
        } catch (IOException e) {
            System.out.println("Error reading notification.");
        }
        System.out.println("Original notification: ");
        System.out.println(noti1.getAttributes().get(0) + " " + noti1.getAttributes().get(1));
        System.out.println(noti1.getMap());
        System.out.println("Notification read from file: ");
        System.out.println(noti2.getAttributes().get(0) + " " + noti2.getAttributes().get(1));
        System.out.println(noti2.getMap());
    }
}

主要 2

public class Main2 {
    public static void main(String[] args) {
        String regFile = "registry.txt";
        String notificationFile = "notification.txt";
        Persistence pers = new Persistence();
        RegisteredUsers reg3 = new RegisteredUsers();

        try {
            reg3 = pers.readReg(regFile);
        } catch (IOException e) {
            System.out.println("Error reading registry.");
        }
        if (reg3 == null) {
            System.out.println("reg3 is null");
        }
        if (reg3.getMap() == null)
            System.out.println("reg3 has a null map");
        if (reg3.getMap().isEmpty())
            System.out.println("reg3 has an empty map");
        
        System.out.println("Registry read from file on another process: ");
        System.out.println(reg3.isRegistered("Name1") + " " + reg3.isRegistered("Name2"));
        
        Notification noti3 = new Notification(); //not necesary but it's the way it's done in the bigger app.
        try {
            noti3 = pers.readNotif(notificationFile);
        } catch (IOException e) {
            System.out.println("Error reading notification.");
        }
        System.out.println("Notification read from file on another process: ");
        System.out.println(noti3.getAttributes().get(0) + " " + noti3.getAttributes().get(1));
        System.out.println(noti3.getMap());
    }
}

A Class 将对象保存在文件中:

public class Persistence {
    public void writeReg(RegisteredUsers regus, String file) throws IOException {
        try(FileOutputStream fos = new FileOutputStream(file);
            ObjectOutputStream oos = new ObjectOutputStream(fos);) {
                oos.writeObject(regus);
                oos.flush();
            }
    }
    
    public RegisteredUsers readReg(String file) throws IOException {
        RegisteredUsers regus = null;
        try(FileInputStream fis = new FileInputStream(file);
            ObjectInputStream ois = new ObjectInputStream(fis);) {
                regus = (RegisteredUsers) ois.readObject();
        } catch (ClassNotFoundException e) {
        System.out.println("Wrong class.");
        }
        return regus;
    }
    
    public void writeNotif(Notification regus, String file) throws IOException {
        try(FileOutputStream fos = new FileOutputStream(file);
            ObjectOutputStream oos = new ObjectOutputStream(fos);) {
                oos.writeObject(regus);
                oos.flush();
            }
    }
    
    public Notification readNotif(String file) throws IOException {
        Notification notif = null;
        try(FileInputStream fis = new FileInputStream(file);
            ObjectInputStream ois = new ObjectInputStream(fis);) {
                notif = (Notification) ois.readObject();
        } catch (ClassNotFoundException e) {
        System.out.println("Wrong class.");
        }
        return notif;
    }
}

注册用户

public class RegisteredUsers implements Serializable {
    private static HashMap<String, User> users;
    
    public RegisteredUsers() {
        users = new HashMap<String, User>();
    }
    
    public HashMap<String, User> getMap() {
        return users;   
    }
    
    public boolean isRegistered(String name) {
        User us = users.get(name);
        return us != null;
    }
    
    public void register(String name, String ip) {
        users.put(name, new User(name, ip, false));
    }
}

通知

public class Notification implements Serializable {
    private ArrayList<String> attributes;
    private HashMap<String, User> map = new HashMap<>();
    
    public Notification() {
    }
    
    public Notification(String name, String ip) {
        attributes = new ArrayList<String>();
        attributes.add(0, name);
        attributes.add(1, ip);
        map.put(ip, new User(name, ip, false));
    }

    public ArrayList<String> getAttributes() {
        return attributes;
    }

    public HashMap<String, User> getMap() {
        return map;
    }
}

用户

public class User implements Serializable {
    private String name;
    private String ip;
    private boolean connection_state;

    public User(String name, String ip, boolean connection_state) {
        this.name = name;
        this.ip = ip;
        this.connection_state = connection_state;
    }
}

在 java static 中,字段是隐式的 transient,瞬态字段未序列化。

如果将RegisterdUsers修改为

public class RegisteredUsers implements Serializable {
    private HashMap<String, User> users; // static modifier is removed
    ...
}

序列化将起作用。