关于List.addAll(Collection<E>)方法遇到的问题
2017-07-13 11:40
746 查看
涉及的软件环境:SpringMVC,fastjson
有一个需求,需要将热词信息跟自定义的热词信息(另外一个实体的信息)合并到一个列表里,
获取hotKeyList的代码
获取自定义热词的代码:
显然最终都是封装成
或者:
都产生了下面的问题:输出到客户端的时候,
而原来的
后来将两个list的合并方式改成对象新对象拷贝旧对象信息,将新对象存入列表的方式,就两个都正常了:
这是什么问题?对象引用的问题?
从上面的运行结果可以看出是
其中方法
Copies an array from the specified source array, beginning at the specified position, to the specified position of the destination array. A subsequence of array components are copied from the source array referenced by src to the destination array referenced by dest. The number of components copied is equal to the length argument. The components at positions srcPos through srcPos+length-1 in the source array are copied into positions destPos through destPos+length-1, respectively, of the destination array.
If the src and dest arguments refer to the same array object, then the copying is performed as if the components at positions srcPos through srcPos+length-1 were first copied to a temporary array with length components and then the contents of the temporary array were copied into positions destPos through destPos+length-1 of the destination array.
第一段话说到”数组组件的子序列从src引用的源数组复制到dest引用的目标数组。”注意“引用的源数组”、“引用的目标数组”的意思。
而通过SpringMVC的
pom.xml 新增jackson的依赖:
spring-mvc.xml修改如下:
还是使用最简单
这次疏忽导致的影响非常大,虽然问题藏得有点深,但关键还是没有去验证对原来数据影响导致,以此作为一次深刻经验教训。
另外,经过集思广益,总结出以上出现$ref的问题的根本是因为对象中存在重复的对象导致,如果仍然使用fastjson方法的话可以这么处理:
FastJson提供了
用法:
得到的是object的json字符串。
有一个需求,需要将热词信息跟自定义的热词信息(另外一个实体的信息)合并到一个列表里,
获取hotKeyList的代码
List<HotKeys> hotKeyList = hotKeysDao.getAllHotKeys();
获取自定义热词的代码:
List<AdInfoExt> comprehensivePageAds = adInfoDao.getAdInfoListByRuleCode("comprehensive_search_page", "ad"); List<HotKeys> cpaKeys = new ArrayList<HotKeys>(); for(AdInfoExt ad : comprehensivePageAds){ HotKeys key = new HotKeys(); key.setHotKey(ad.getAdTittle()); key.setStats(1); key.setUrl(ad.getUrl()); cpaKeys.add(key); }
显然最终都是封装成
List<HotKeys>了,然后将
hotKeyList、
cpaKeys合并到一起用了:
cpaKeys.addAll(hotKeyList);
或者:
for(HotKeys k : hotKeyList){ cpaKeys.add(k); }
都产生了下面的问题:输出到客户端的时候,
cpaKeys是正常的,
"cpaKey": [ { "k": "杨振宁遗产分配", "sta": 0, "u": "https://wap.sogou.com/web/searchList.jsp?keyword=%E6%9D%A8%E6%8C%AF%E5%AE%81%E9%81%97%E4%BA%A7%E5%88%86%E9%85%8D&pid=sogou-mobp-eeea8c180c5dff16&v=5" }, { "k": "泉州6车追尾", "sta": 0, "u": "https://wap.sogou.com/web/searchList.jsp?keyword=%E6%B3%89%E5%B7%9E6%E8%BD%A6%E8%BF%BD%E5%B0%BE&pid=sogou-mobp-eeea8c180c5dff16&v=5" }, { "k": "翻车致19人遇难", "sta": 1, "u": "https://wap.sogou.com/web/searchList.jsp?keyword=%E7%BF%BB%E8%BD%A6%E8%87%B419%E4%BA%BA%E9%81%87%E9%9A%BE&pid=sogou-mobp-eeea8c180c5dff16&v=5" } ]
而原来的
hotKeyList的数据就变成了以下的模样(它正确的样子应该跟上面的
cpaKey一样):
"hotKey": [ { "$ref": "$.cpaKey[0]" }, { "$ref": "$.cpaKey[1]" }, { "$ref": "$.cpaKey[2]" }, { "$ref": "$.cpaKey[3]" }, { "$ref": "$.cpaKey[4]" }, { "$ref": "$.cpaKey[5]" }, { "$ref": "$.cpaKey[6]" }, { "$ref": "$.cpaKey[7]" } ]
后来将两个list的合并方式改成对象新对象拷贝旧对象信息,将新对象存入列表的方式,就两个都正常了:
for(HotKeys key : hotKeyList){ HotKeys k = new HotKeys(); BeanUtils.copyProperties(key, k); cpaKeys.add(k); }
这是什么问题?对象引用的问题?
从上面的运行结果可以看出是
hotKeyList里面的对象引用发生变化,转而指向
cpaKeys中对应的数据,经过
addAll()方法处理后
hotKeyList只保存了每个对象的引用信息(或者说指针)。
hotKeyList并没有另外生成一份数据,看看源码:
public boolean addAll(Collection<? extends E> c) { Object[] a = c.toArray(); int numNew = a.length; ensureCapacityInternal(size + numNew); // Increments modCount System.arraycopy(a, 0, elementData, size, numNew); size += numNew; return numNew != 0; }
其中方法
System.arraycopy(a, 0, elementData, size, numNew);的描述如下:
Copies an array from the specified source array, beginning at the specified position, to the specified position of the destination array. A subsequence of array components are copied from the source array referenced by src to the destination array referenced by dest. The number of components copied is equal to the length argument. The components at positions srcPos through srcPos+length-1 in the source array are copied into positions destPos through destPos+length-1, respectively, of the destination array.
If the src and dest arguments refer to the same array object, then the copying is performed as if the components at positions srcPos through srcPos+length-1 were first copied to a temporary array with length components and then the contents of the temporary array were copied into positions destPos through destPos+length-1 of the destination array.
第一段话说到”数组组件的子序列从src引用的源数组复制到dest引用的目标数组。”注意“引用的源数组”、“引用的目标数组”的意思。
而通过SpringMVC的
@ResponseBody返回JSON的时候,FastJSON并没有将引用转成数据,为了避免日后还会产生这样的问题,最终的解决方案是将FastJSON换为Jackson。配置文件修改如下:
pom.xml 新增jackson的依赖:
<dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-databind</artifactId> <version>2.4.2</version> </dependency>
spring-mvc.xml修改如下:
<!--避免IE执行AJAX时,返回JSON出现下载文件.原来的(fastjson)class="com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter"--> <bean id="mappingJacksonHttpMessageConverter" class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter"> <property name="supportedMediaTypes"> <list> <value>text/html;charset=UTF-8</value> <value>application/json</value> </list> </property> <!-- 使用jackson不需要这个 <property name="features"> <list> <!// <value>WriteMapNullValue</value> //> <value>QuoteFieldNames</value> </list> </property> --> </bean> <!-- 修改新增 --> <bean id="stringHttpMessageConverter" class="org.springframework.http.converter.StringHttpMessageConverter"> <property name="supportedMediaTypes"> <list> <value>text/plain;charset=UTF-8</value> </list> </property> </bean> <!-- 修改新增 --> <bean id="formHttpMessageConverter" class="org.springframework.http.converter.FormHttpMessageConverter" /> <!-- 启动SpringMVC的注解功能,完成请求和注解POJO的映射 --> <bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter"> <property name="messageConverters"> <list> <ref bean="formHttpMessageConverter" /> <!-- 修改新增 --> <ref bean="stringHttpMessageConverter" /> <!-- 修改新增 --> <ref bean="mappingJacksonHttpMessageConverter" /> <!-- JSON转换器 --> </list> </property> </bean>
还是使用最简单
addAll()方法,结果正常。
这次疏忽导致的影响非常大,虽然问题藏得有点深,但关键还是没有去验证对原来数据影响导致,以此作为一次深刻经验教训。
另外,经过集思广益,总结出以上出现$ref的问题的根本是因为对象中存在重复的对象导致,如果仍然使用fastjson方法的话可以这么处理:
FastJson提供了
SerializerFeature.DisableCircularReferenceDetect这个序列化选项,用来关闭引用检测。关闭引用检测后,重复引用对象时就不会被$ref代替,但是在循环引用时也会导致StackOverflowError异常。
用法:
JSON.toJSONString(object, SerializerFeature.DisableCircularReferenceDetect);
得到的是object的json字符串。
相关文章推荐
- 关于List<E>.addAll(Collection<? extends E> collection)传入参数null
- 关于<asp:checkBoxList>控件的对齐方法
- 关于<asp:checkBoxList>控件的对齐方法
- 关于List<>的循环添加与读取问题
- 关于List<T>和ArrayList<T>执行效率问题
- 解决方法:关于问题 "C++ - Unresolved inclusion: <iostream>"
- 关于servlet服务端接收客户端发送的List<?>数据的问题
- 关于八数码问题中的状态判重的三种解决方法(编码、hash、<set>)
- 关于ionic指令 <ion-infinite-scroll ng-if="moreDataCanBeLoaded()" icon="ion-loading-c" on-infinite="loadMoreData()" distance=1%> </ion-infinite-scroll> 运用中遇到的问题
- 利用out关键字向函数传递List<T>参数遇到的问题
- 关于html中charset与<title>位置不同页面空白的问题及解决方法
- VM8.0下安装遇到了问题“windows cannot read the<product key> setting from the unattend answer file”解决方法
- 关于List<Model>类型 GridView排序问题的解决
- 关于ServletFileUpload中parseRequest(request)返回的list<FileItem>为空的问题
- 关于Random 和 List<int>的Exist的方法使用
- VM8.0下安装遇到了问题“windows cannot read the<product key> setting from the unattend answer file”解决方法
- List<T>方法调用线程同步问题
- C#中泛型集合List<T>反序列化问题及解决方法
- asp.net mvc 2 简简单单做开发 使用DataContext扩展方法Find<TEntity>(TEntity obj) 遇到的问题
- java中addAll(Collection<? extends E> col)方法实例