Java LinkedHashMap转换为Object后被序列化为另一个类?

huangapple go评论67阅读模式
英文:

Java LinkedHashMap converted to Object is serialized as another class?

问题

我正在尝试将一个LinkedHashMap序列化为要写入ObjectOutputStream的内容,但我遇到了一些奇怪的情况。ObjectOutputStream写入了将LinkedHashMap转换为Object的内容,但它不是一个LinkedHashMap,而是被写入为我的名为SQLRow的类?!

Host.instance.getLogger().info("Sending back player data...");
final LinkedHashMap<String, NetworkedSQLObject> hm = MirageSQLTables.players.getByPrimaryKey(rest.readUTF()).getAsSocketEligibleMap();
Host.instance.getLogger().info("Linked Hash Map class name: " + hm.getClass().getName());
c.sendMessage(new SQLObjectResponsePacket(pID, (Object)hm));

注意:函数getByPrimaryKey()是一个自定义的SQL函数,返回我的自定义类SQLRow

上面代码的输出:

14:37:03 [INFO] [Host] Sending back player data...
14:37:03 [INFO] [Host] 获取列: id
14:37:03 [INFO] [Host] 获取列: name
14:37:03 [INFO] [Host] 获取列: date_joined
14:37:03 [INFO] [Host] 获取列: rank
14:37:03 [INFO] [Host] 获取列: moderator
14:37:03 [INFO] [Host] 添加 NetworkedSQLObject: id:TEXT -> 2
14:37:03 [INFO] [Host] 添加 NetworkedSQLObject: name:TEXT -> KrispWasntTaken
14:37:03 [INFO] [Host] 添加 NetworkedSQLObject: date_joined:TIMESTAMP -> 2023-06-14 18:19:15.0
14:37:03 [INFO] [Host] 添加 NetworkedSQLObject: rank:INT -> 0
14:37:03 [INFO] [Host] 添加 NetworkedSQLObject: moderator:BIT -> true
14:37:03 [INFO] [Host] Linked Hash Map 类名: mirage.database.sql.SQLRow$1 <---- 在这里!

在NetworkedSQLObject构造函数中也显示了相同的内容。函数getAsSocketEligibleMap()在SQLRow类内部,但我真的很困惑,因为它与该类没有关联,返回的是一个全新的LinkedHashMap,而不是一个SQLRow的实例...

getAsSocketEligibleMap()的代码:

public LinkedHashMap<String, NetworkedSQLObject> getAsSocketEligibleMap(){
    return new LinkedHashMap<>(){
        {
            Set<Map.Entry<String, SQLObject>> es = data.entrySet();

            Iterator<Map.Entry<String, SQLObject>> i = es.iterator();

            while(i.hasNext()){
                Map.Entry<String, SQLObject> entry = i.next();
                Host.instance.getLogger().info("添加 NetworkedSQLObject: " + entry.getKey() + ':' + entry.getValue().getType() + " -> " + entry.getValue().getValue());
                put(entry.getKey(), new NetworkedSQLObject(entry.getValue()));
            }
        }
    };
}

任何帮助都将不胜感激...

英文:

I am trying to serialize a LinkedHashMap to be written to an ObjectOutputStream, but I've encountered something strange. The ObjectOutputStream, writes the LinkedHashMap converted to an Object, however it is not a LinkedHashMap, it is writted as my class called SQLRow?!

Host.instance.getLogger().info(&quot;Sending back player data...&quot;);
final LinkedHashMap&lt;String, NetworkedSQLObject&gt; hm = MirageSQLTables.players.getByPrimaryKey(rest.readUTF()).getAsSocketEligibleMap();
Host.instance.getLogger().info(&quot;Linked Hash Map class name: &quot; + hm.getClass().getName());
c.sendMessage(new SQLObjectResponsePacket(pID, (Object)hm));

NOTE: The function getByPrimaryKey() is a custom SQL function that returns my custom class, SQLRow.

output of code above:


14:37:03 [INFO] [Host] Sending back player data...
14:37:03 [INFO] [Host] Getting col: id
14:37:03 [INFO] [Host] Getting col: name
14:37:03 [INFO] [Host] Getting col: date_joined
14:37:03 [INFO] [Host] Getting col: rank
14:37:03 [INFO] [Host] Getting col: moderator
14:37:03 [INFO] [Host] adding NetworkedSQLObject: id:TEXT -&gt; 2
14:37:03 [INFO] [Host] adding NetworkedSQLObject: name:TEXT -&gt; KrispWasntTaken
14:37:03 [INFO] [Host] adding NetworkedSQLObject: date_joined:TIMESTAMP -&gt; 2023-06-14 18:19:15.0
14:37:03 [INFO] [Host] adding NetworkedSQLObject: rank:INT -&gt; 0
14:37:03 [INFO] [Host] adding NetworkedSQLObject: moderator:BIT -&gt; true
14:37:03 [INFO] [Host] Linked Hash Map class name: mirage.database.sql.SQLRow$1 &lt;---- HERE!

It says the same thing in the NetworkedSQLObject constructor. The function getAsSocketEligibleMap() is INSIDE the SQLRow class, but I am really confused as it has no ties to the class and returns a fresh new LinkedHashMap, not an instance of a SQLRow...

getAsSocketEligibleMap() code:


public LinkedHashMap&lt;String, NetworkedSQLObject&gt; getAsSocketEligibleMap(){
        return new LinkedHashMap&lt;&gt;(){{
            Set&lt;Map.Entry&lt;String, SQLObject&gt;&gt; es = data.entrySet();

            Iterator&lt;Map.Entry&lt;String, SQLObject&gt;&gt; i = es.iterator();

            while(i.hasNext()){
                Map.Entry&lt;String, SQLObject&gt; entry = i.next();
                Host.instance.getLogger().info(&quot;adding NetworkedSQLObject: &quot; + entry.getKey() + &#39;:&#39; + entry.getValue().getType() + &quot; -&gt; &quot; + entry.getValue().getValue());
                put(entry.getKey(), new NetworkedSQLObject(entry.getValue()));
            }
        }};
    }

Any help is appreciated...

答案1

得分: 2

你在你的类中使用了双括号初始化模式,这通常不是一个理想的模式(双{{}})。这实际上定义了一个新的内部类。所以你并没有返回一个实际的LinkedHashMap,而是返回了一个匿名内部类,它继承自LinkedHashMap。由于它是一个内部类,它还保留了对外部类的引用,在这种情况下,就是你的SQLRow类。简单地移除双括号初始化模式应该可以解决你的问题。(这是应该避免使用这种模式的众多原因之一)。

英文:

You have used the double brace initialization pattern in your class, which is generally not a desirable pattern (the double {{}}). What that does is effectively define a new, inner class. So you are not returning an actual LinkedHashMap, you are returning an anonymous inner class which extends from LinkedHashMap. Since it is an inner class, it also retains a reference to the outer class, in this case, your SQLRow class. Simply removing the double brace initialization pattern should solve your problem. (this is one of the many reasons the pattern should be avoided).

huangapple
  • 本文由 发表于 2023年6月15日 21:47:53
  • 转载请务必保留本文链接:https://go.coder-hub.com/76483165.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定