为什么这个 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
...
}
序列化将起作用。
上下文
我制作了一个 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
...
}
序列化将起作用。