【问题标题】:Flexjson or Gson : Protect object references after object serializationFlexjson 或 Gson :在对象序列化后保护对象引用
【发布时间】:2014-09-11 14:13:06
【问题描述】:

我用flexjson 序列化一个列表。序列化后,我打印对象hashcode() 并检查对象是否相等。

问题,操作后对象引用发生变化。我不想要它。

我的代码;

    String sameOfString="sameOfString";
    List<Object> list=new ArrayList<Object>();
    list.add(sameOfString);
    list.add(sameOfString);
    list.add("differentString");

    for(Object str:list){
        System.out.println(str.hashCode());
    }
    **System.out.println(list.get(0)==list.get(1));**
    System.out.println(list.get(0)==list.get(2));
    System.out.println("--");
    String json= new JSONSerializer().exclude("*.class").deepSerialize(list);
    List<String> listDeserilized = (List<String>) new JSONDeserializer().deserialize(json);
    for(Object str:listDeserilized){
        System.out.println(str.hashCode());
    }
    **System.out.println(listDeserilized.get(0)==listDeserilized.get(1));**
    System.out.println(listDeserilized.get(0)==listDeserilized.get(2));

然后输出..

1018069468

1018069468

199675306

-

1018069468

1018069468

199675306

如何解决这个问题?

【问题讨论】:

    标签: java json gson flexjson


    【解决方案1】:

    我用 jackson lib 解决了我的问题

    @JsonIdentityInfo注解保护对象关系(换句话说;保护引用) 反序列化后,对象位置在内存中不会改变。

    最终代码:

    package com.maar.projectbuilder;
    
    import com.fasterxml.jackson.annotation.JsonIdentityInfo;
    import com.fasterxml.jackson.annotation.JsonTypeInfo;
    import com.fasterxml.jackson.annotation.JsonTypeName;
    import com.fasterxml.jackson.annotation.ObjectIdGenerators;
    import com.fasterxml.jackson.core.JsonProcessingException;
    import com.fasterxml.jackson.core.type.TypeReference;
    import com.fasterxml.jackson.databind.ObjectMapper;
    import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
    
    import java.io.IOException;
    import java.util.ArrayList;
    import java.util.List;
    
    /**
     * Created by Firat on 11.9.2014.
     */
    public class Testt {
        @JsonDeserialize(as=StringClazz.class)
        @JsonTypeInfo(use=JsonTypeInfo.Id.CLASS, include=JsonTypeInfo.As.PROPERTY, property="@class")
        @JsonIdentityInfo(generator=ObjectIdGenerators.IntSequenceGenerator.class, property="@id")
        @JsonTypeName(value = "StringClazz")
        private static class StringClazz{
            private String data="";
    
            public StringClazz() {
            }
    
            public String getData() {
                return data;
            }
    
            public void setData(String data) {
                this.data = data;
            }
        }
        public static void main(String[] args) throws IOException {
            StringClazz someOfString=new StringClazz();
            someOfString.setData("someOfString");
            StringClazz differentString=new StringClazz();
            differentString.setData("differentString");
    
            List<StringClazz> list=new ArrayList<StringClazz>();
            list.add(someOfString);
            list.add(someOfString);
            list.add(differentString);
    
            for(Object str:list){
                System.out.println(str.hashCode());
            }
            System.out.println(list.get(0)==list.get(1));
            System.out.println(list.get(0)==list.get(2));
            System.out.println("-------");
            String json= null;
            try {
                json = new ObjectMapper().enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL).writeValueAsString(list);
            } catch (JsonProcessingException e) {
                e.printStackTrace();
            }
            System.out.println(json);
            List<StringClazz> listDeserilized =new ObjectMapper().enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL).readValue(json, new TypeReference<List<StringClazz>>() {
            });
            for(Object str:listDeserilized){
                System.out.println(str.hashCode());
            }
            System.out.println(listDeserilized.get(0)==listDeserilized.get(1));
            System.out.println(listDeserilized.get(0)==listDeserilized.get(2));
        }
    }
    

    【讨论】:

      【解决方案2】:

      如何解决这个问题?

      你没有。反序列化一个对象意味着在内存中的不同位置创建一个新实例。

      但是,我不推荐这样做,您可以保留一个对象注册表(可能是HashMap),执行反序列化,检查注册表是否包含该对象,然后替换它与现有的。

      String 类已经为您提供了一些这种实习行为。见String#intern()

      【讨论】:

      • String.intern() 将不允许垃圾收集器在您停止使用它时丢弃内存。它永久存在于内存中,无法回收。如果您想构建一个稳定而健壮的应用程序,我强烈建议您避免使用它。
      【解决方案3】:

      你正在苦苦挣扎的是什么是平等?在 Java 中有两个版本的相等(与许多现代语言一样)。

      1. 这些对象的值是否相等?
      2. 这些对象是同一个对象吗? (即通过引用)

      这分别是 .equals() 和 == 之间的区别。当您反序列化某些内容时,它会创建一个新对象,因此如果您有另一个您序列化的对象副本。它永远不会是数字 2 相等(即通过引用相等)。因为反序列化被赋予了 JSON 表示,并从中创建了一个新的对象图。

      但它可能是 .equals(),前提是您的对象正确定义了 .equals() 对包含的所有对象的含义。默认情况下 Object.equals() 比较引用并且与 == 相同。但是,每个对象都可以重载它,并且在 String.equals() 的情况下会比较字符串的实际内容。

      因此,只需将您的代码更改为使用 .equals() 而不是 == 即可获得您所期望的结果:

      System.out.println( list.get(0).equals( list.get(1) ) )
      System.out.println( list.get(0).equals( list.get(2) ) )
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2013-07-18
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多