使用自定义序列化对象序列化 HashMap
Serializing HashMap with a custom serialized object
我在 ActionHandler 中声明了 HashMap class:
public class ActionHandler {
private HashMap<Cooldown, Long> cooldowns = new HashMap<Cooldown, Long>();
public void disInit(Main main) throws FileNotFoundException, IOException{
String path = main.getDataFolder() + File.separator + "cooldowns.dat";
File serialize = new File(path);
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(serialize));
oos.writeObject(cooldowns);
oos.flush();
oos.close();
serialize.createNewFile();
}
}
public class Cooldown implements Serializable{
private static final long serialVersionUID = 2233153996259053084L;
private String username;
private Shop shop;
public Cooldown(String username, Shop shop){
//constructing setting the fields...
}
public String getUsername(){//returning the fields
public Shop getShop(){//return shop;}
}
只要插件序列化文件(使用 disInit),控制台就会报出这个错误。我很兴奋,因为我已经为我的冷却 class.
实现了 Serializable
[21:16:29 WARN]: java.io.NotSerializableException: com.gmail.ketracoder.vts.Main
[21:16:29 WARN]: at java.io.ObjectOutputStream.writeObject0(ObjectOutputS
tream.java:1184)
[21:16:29 WARN]: at java.io.ObjectOutputStream.defaultWriteFields(ObjectO
utputStream.java:1548)
[21:16:29 WARN]: at java.io.ObjectOutputStream.writeSerialData(ObjectOutp
utStream.java:1509)
[21:16:29 WARN]: at java.io.ObjectOutputStream.writeOrdinaryObject(Object
OutputStream.java:1432)
[21:16:29 WARN]: at java.io.ObjectOutputStream.writeObject0(ObjectOutputS
tream.java:1178)
[21:16:29 WARN]: at java.io.ObjectOutputStream.defaultWriteFields(ObjectO
utputStream.java:1548)
[21:16:29 WARN]: at java.io.ObjectOutputStream.writeSerialData(ObjectOutp
utStream.java:1509)
[21:16:29 WARN]: at java.io.ObjectOutputStream.writeOrdinaryObject(Object
OutputStream.java:1432)
[21:16:29 WARN]: at java.io.ObjectOutputStream.writeObject0(ObjectOutputS
tream.java:1178)
[21:16:29 WARN]: at java.io.ObjectOutputStream.writeObject(ObjectOutputSt
ream.java:348)
[21:16:29 WARN]: at java.util.HashMap.internalWriteEntries(HashMap.java:1
776)
[21:16:29 WARN]: at java.util.HashMap.writeObject(HashMap.java:1354)
[21:16:29 WARN]: at sun.reflect.NativeMethodAccessorImpl.invoke0(Native M
ethod)
[21:16:29 WARN]: at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMet
hodAccessorImpl.java:62)
[21:16:29 WARN]: at sun.reflect.DelegatingMethodAccessorImpl.invoke(Deleg
atingMethodAccessorImpl.java:43)
[21:16:29 WARN]: at java.lang.reflect.Method.invoke(Method.java:483)
[21:16:29 WARN]: at java.io.ObjectStreamClass.invokeWriteObject(ObjectStr
eamClass.java:988)
[21:16:29 WARN]: at java.io.ObjectOutputStream.writeSerialData(ObjectOutp
utStream.java:1496)
[21:16:29 WARN]: at java.io.ObjectOutputStream.writeOrdinaryObject(Object
OutputStream.java:1432)
[21:16:29 WARN]: at java.io.ObjectOutputStream.writeObject0(ObjectOutputS
tream.java:1178)
[21:16:29 WARN]: at java.io.ObjectOutputStream.writeObject(ObjectOutputSt
ream.java:348)
[21:16:29 WARN]: at com.gmail.ketracoder.vts.Shop.ActionHandler.disInit(A
ctionHandler.java:39)
[21:16:29 WARN]: at com.gmail.ketracoder.vts.Main.onDisable(Main.java:165
)
[21:16:29 WARN]: at org.bukkit.plugin.java.JavaPlugin.setEnabled(JavaPlug
in.java:323)
[21:16:29 WARN]: at org.bukkit.plugin.java.JavaPluginLoader.disablePlugin
(JavaPluginLoader.java:359)
[21:16:29 WARN]: at org.bukkit.plugin.SimplePluginManager.disablePlugin(S
implePluginManager.java:424)
[21:16:29 WARN]: at org.bukkit.plugin.SimplePluginManager.disablePlugins(
SimplePluginManager.java:417)
[21:16:29 WARN]: at org.bukkit.craftbukkit.v1_8_R1.CraftServer.disablePlu
gins(CraftServer.java:334)
[21:16:29 WARN]: at net.minecraft.server.v1_8_R1.MinecraftServer.stop(Min
ecraftServer.java:430)
[21:16:29 WARN]: at net.minecraft.server.v1_8_R1.MinecraftServer.run(Mine
craftServer.java:561)
[21:16:29 WARN]: at java.lang.Thread.run(Thread.java:745)
我唯一一次在 HashMap 中放入东西,是在我调用时:
private void setCooldown(Player player, int slot, Main main, Shop shop){
String playerName = player.getName();
Cooldown cooldown = new Cooldown(playerName, shop);
cooldowns.put(cooldown, System.currentTimeMillis());
}
The Cooldown
class is what is causing the problem
不,Main
class 是导致问题的原因,如异常所述:
java.io.NotSerializableException: com.gmail.ketracoder.vts.Main
显然 Cooldown
是 Main
的内部 class,因此它保留了对封闭对象的引用,该对象不可序列化。使其成为静态 class 或外部 class.
注意在您调用它的地方调用 createNewFile()
将产生一个零长度的文件。您不需要在任何地方这样做:new FileOutputStream(...)
已经这样做了。删除它即可。
如果你寻找一个非java.io
相关的方法,从最深的stacktrace条目开始,你会发现java.util.HashMap.writeObject
负责存储包含的对象 在 Map
中。如果在此过程中遇到像 com.gmail.ketracoder.vts.Main
这样的非 Serializable
对象,很明显您必须在尝试序列化它之前将其放入映射中,作为键或值(好吧,或两者兼而有之)。
如果要序列化地图,地图中包含的所有对象必须是Serializable
。不像,例如AWT 组件上的侦听器,不会跳过非 Serializable
对象。
但请注意,您的所作所为很危险。如果 Main
的实例包含在地图中,而 Main
又将引用地图(我猜是从 class 名称),你有一个循环引用.虽然序列化原则上适用于循环对象图,但当它们与 HashMap
s 结合时,它将非常脆弱。 HashMap
需要在恢复映射时重新散列所有元素,这可能会导致在循环对象图的情况下对不完整的对象调用 hashCode
和 equals
。
我在 ActionHandler 中声明了 HashMap class:
public class ActionHandler {
private HashMap<Cooldown, Long> cooldowns = new HashMap<Cooldown, Long>();
public void disInit(Main main) throws FileNotFoundException, IOException{
String path = main.getDataFolder() + File.separator + "cooldowns.dat";
File serialize = new File(path);
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(serialize));
oos.writeObject(cooldowns);
oos.flush();
oos.close();
serialize.createNewFile();
}
}
public class Cooldown implements Serializable{
private static final long serialVersionUID = 2233153996259053084L;
private String username;
private Shop shop;
public Cooldown(String username, Shop shop){
//constructing setting the fields...
}
public String getUsername(){//returning the fields
public Shop getShop(){//return shop;}
}
只要插件序列化文件(使用 disInit),控制台就会报出这个错误。我很兴奋,因为我已经为我的冷却 class.
实现了 Serializable[21:16:29 WARN]: java.io.NotSerializableException: com.gmail.ketracoder.vts.Main
[21:16:29 WARN]: at java.io.ObjectOutputStream.writeObject0(ObjectOutputS
tream.java:1184)
[21:16:29 WARN]: at java.io.ObjectOutputStream.defaultWriteFields(ObjectO
utputStream.java:1548)
[21:16:29 WARN]: at java.io.ObjectOutputStream.writeSerialData(ObjectOutp
utStream.java:1509)
[21:16:29 WARN]: at java.io.ObjectOutputStream.writeOrdinaryObject(Object
OutputStream.java:1432)
[21:16:29 WARN]: at java.io.ObjectOutputStream.writeObject0(ObjectOutputS
tream.java:1178)
[21:16:29 WARN]: at java.io.ObjectOutputStream.defaultWriteFields(ObjectO
utputStream.java:1548)
[21:16:29 WARN]: at java.io.ObjectOutputStream.writeSerialData(ObjectOutp
utStream.java:1509)
[21:16:29 WARN]: at java.io.ObjectOutputStream.writeOrdinaryObject(Object
OutputStream.java:1432)
[21:16:29 WARN]: at java.io.ObjectOutputStream.writeObject0(ObjectOutputS
tream.java:1178)
[21:16:29 WARN]: at java.io.ObjectOutputStream.writeObject(ObjectOutputSt
ream.java:348)
[21:16:29 WARN]: at java.util.HashMap.internalWriteEntries(HashMap.java:1
776)
[21:16:29 WARN]: at java.util.HashMap.writeObject(HashMap.java:1354)
[21:16:29 WARN]: at sun.reflect.NativeMethodAccessorImpl.invoke0(Native M
ethod)
[21:16:29 WARN]: at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMet
hodAccessorImpl.java:62)
[21:16:29 WARN]: at sun.reflect.DelegatingMethodAccessorImpl.invoke(Deleg
atingMethodAccessorImpl.java:43)
[21:16:29 WARN]: at java.lang.reflect.Method.invoke(Method.java:483)
[21:16:29 WARN]: at java.io.ObjectStreamClass.invokeWriteObject(ObjectStr
eamClass.java:988)
[21:16:29 WARN]: at java.io.ObjectOutputStream.writeSerialData(ObjectOutp
utStream.java:1496)
[21:16:29 WARN]: at java.io.ObjectOutputStream.writeOrdinaryObject(Object
OutputStream.java:1432)
[21:16:29 WARN]: at java.io.ObjectOutputStream.writeObject0(ObjectOutputS
tream.java:1178)
[21:16:29 WARN]: at java.io.ObjectOutputStream.writeObject(ObjectOutputSt
ream.java:348)
[21:16:29 WARN]: at com.gmail.ketracoder.vts.Shop.ActionHandler.disInit(A
ctionHandler.java:39)
[21:16:29 WARN]: at com.gmail.ketracoder.vts.Main.onDisable(Main.java:165
)
[21:16:29 WARN]: at org.bukkit.plugin.java.JavaPlugin.setEnabled(JavaPlug
in.java:323)
[21:16:29 WARN]: at org.bukkit.plugin.java.JavaPluginLoader.disablePlugin
(JavaPluginLoader.java:359)
[21:16:29 WARN]: at org.bukkit.plugin.SimplePluginManager.disablePlugin(S
implePluginManager.java:424)
[21:16:29 WARN]: at org.bukkit.plugin.SimplePluginManager.disablePlugins(
SimplePluginManager.java:417)
[21:16:29 WARN]: at org.bukkit.craftbukkit.v1_8_R1.CraftServer.disablePlu
gins(CraftServer.java:334)
[21:16:29 WARN]: at net.minecraft.server.v1_8_R1.MinecraftServer.stop(Min
ecraftServer.java:430)
[21:16:29 WARN]: at net.minecraft.server.v1_8_R1.MinecraftServer.run(Mine
craftServer.java:561)
[21:16:29 WARN]: at java.lang.Thread.run(Thread.java:745)
我唯一一次在 HashMap 中放入东西,是在我调用时:
private void setCooldown(Player player, int slot, Main main, Shop shop){
String playerName = player.getName();
Cooldown cooldown = new Cooldown(playerName, shop);
cooldowns.put(cooldown, System.currentTimeMillis());
}
The
Cooldown
class is what is causing the problem
不,Main
class 是导致问题的原因,如异常所述:
java.io.NotSerializableException: com.gmail.ketracoder.vts.Main
显然 Cooldown
是 Main
的内部 class,因此它保留了对封闭对象的引用,该对象不可序列化。使其成为静态 class 或外部 class.
注意在您调用它的地方调用 createNewFile()
将产生一个零长度的文件。您不需要在任何地方这样做:new FileOutputStream(...)
已经这样做了。删除它即可。
如果你寻找一个非java.io
相关的方法,从最深的stacktrace条目开始,你会发现java.util.HashMap.writeObject
负责存储包含的对象 在 Map
中。如果在此过程中遇到像 com.gmail.ketracoder.vts.Main
这样的非 Serializable
对象,很明显您必须在尝试序列化它之前将其放入映射中,作为键或值(好吧,或两者兼而有之)。
如果要序列化地图,地图中包含的所有对象必须是Serializable
。不像,例如AWT 组件上的侦听器,不会跳过非 Serializable
对象。
但请注意,您的所作所为很危险。如果 Main
的实例包含在地图中,而 Main
又将引用地图(我猜是从 class 名称),你有一个循环引用.虽然序列化原则上适用于循环对象图,但当它们与 HashMap
s 结合时,它将非常脆弱。 HashMap
需要在恢复映射时重新散列所有元素,这可能会导致在循环对象图的情况下对不完整的对象调用 hashCode
和 equals
。