【Java】链表中存储对象的问题
更新:
在一次搜索“变量声明在循环体内还是循环体外”问题时,碰见了一个这样的代码,与本文类似,代码如下:
Document [] old ......//这是数据源
EntityDocument[] newArray = new EntityDocument[old.length];//自定义的类,为了把Document里数据保留下来避免Document被关联对象关闭而导致无法取出数据。
EntityDocument d = new EntityDocument();
for(int i=0;i<old.length;i++){
d.content = old[i].getContent();
d.key = old[i].getKey();
d......................
newArray[i] = d;//如此对象重用.....
}
上面的代码最终结果会导致newArray数组中的每个元素都等于最后一个元素,原因就是每次向newArray中存储对象时,没有新建一个对象进行储存,从而导致错误。
上面代码只需要将第3行的 EntityDocument d = new EntityDocument(); 放入循环体内即可实现正常功能。
这种错误隐藏得比较深,所以要好好记住。
原文
在刷《剑指OFFER》的时候,自己犯了一个错误,发现:在链表中存储一个对象时,如果该对象是不断变化的,则应该创建一个新的对象复制该对象的内容(而不是指向同一个对象),将这个新的对象存储到链表中。如果直接存储该对象的话,链表中的对象也会不断变化。基本数据类型和String则没有这种问题。
其实这归根结底是一个传值和传引用的问题:
1.如果存储到链表中的是对象,则存储的是引用(地址),所以该地址上的内容变化时,会引起对象的变化。
2.如果存到链表中的是基本数据类型或者String,存储的就是该数值,不会再发生变化了。(其实String是对象,存储的是引用,后面讨论)。
举个例子:
import java.util.ArrayList; public class Test {
public static class Person {
int age=1;
}
public static void main(String[] args) {
//=======ArrayList存储String或者基础数据类型=========
ArrayList<String> list = new ArrayList<>();
String aString="abc";
list.add(aString);
System.out.println("before:"+list.toString());
aString="123";
System.out.println("after:"+list.toString()); //========ArrayList存储对象=======
ArrayList<Person> pList = new ArrayList<>();
Person a = new Person();
Person b = new Person();
b = a;
Person c = new Person();
c.age=a.age;
pList.add(a);
pList.add(b);
pList.add(c); System.out.print("before:");
for (Person person : pList) {
System.out.print(person.age+" "); //a,b,c的age此时都是1
}
System.out.println(); a.age=2;
System.out.print("after:");
for (Person person : pList) {
System.out.print(person.age+" "); //输出:2,2,1
}
//关键原因:b是和a指向同一个对象,c不是同一个对象
}
}
before:[abc]
after:[abc]
before:
after:
上面的代码可以知道,存储Person这个对象时(存储的是地址),b和a其实是同一个地址,所以a指向的对象改变,会引起链表中的前两个结点(地址相同)改变,而如果要使存进链表的person存储的是a存储时的状态,只能新建一个对象c,令c的内容等于a,才在后面不会发生变化(因为该地址指向的内容没有再发生改变了)。
关于String的讨论:其实String也是对象,存储的其实也是引用(地址),但为什么上面代码中before和after输出的内容都是“abc”呢?其实在aString="123";时,相当于aString=new String("123"),即aString指向了另一个对象,aString存储的地址变成了“123”的地址,但链表中存储的还是“abc”的地址,所以链表中的内容不变。
更详细的传递讨论:值传递和引用传递讨论
【Java】链表中存储对象的问题的更多相关文章
- JAVA链表中迭代器的实现
注:本文代码出自<java数据结构和算法>一书. PS:本文中类的名字定义存在问题,Link9应改为Link.LinkList9应该为LinkList.由于在同包下存在该名称,所以在后面接 ...
- Java 开发中的对象拷贝
前言 在 Java 开发中,很多时候需要将两个属性基本相同的对象进行属性复制,比如 DO 转 VO等等. 本文主要介绍自己实现的简易拷贝工具类与 Spring 提供的属性拷贝的对比. Spring 提 ...
- COM结构化存储中存储对象或者流对象的命名规则
COM结构化存储中存储对象或者流对象的命名规则
- java内存中的对象
前记:几天前,在浏览网页时偶然的发现一道以前就看过很多遍的面试题,题目是:“请说出‘equals’和‘==’的区别”,当时我觉得我还是挺懂的,在心里答了一点(比如我们都知道的:‘==’比较两个引用是否 ...
- 面试题:JVM在Java堆中对对象的创建、内存结构、访问方式
一.对象创建过程 1.检查类是否已被加载 JVM遇到new指令时,首先会去检查这个指令参数能否在常量池中定位到这个类的符号引用,检查这个符号引用代表的类是否已被加载.解析.初始化,若没有,则进行类加载 ...
- Java操作Redis存储对象类型数据
背景描述 关于JAVA去操作Redis时,如何存储一个对象的数据,大家是非常关心的问题,虽然官方提供了存储String,List,Set等等类型,但并不满足我们现在实际应用.存储一个对象是是 ...
- 在localStorage中存储对象数组并读取
频繁ajax请求导致页面响应变慢. 于是考虑将数据存储在window.storage中,这样只请求一次ajax,而不需要频繁请求. 鉴于localstorage中只能存储字符串,所以我们要借助于JSO ...
- Java连接Redis,存储对象获取对象()byte和json),连接池
Java连接Redis Jedis连接Redis,Lettuce连接Redis Jedis连接Redis 1. 创建maven项目 2. 引入依赖 <dependencies> <d ...
- java list中的对象去重原理
/******************************************************************************* * * Copyright (c) W ...
随机推荐
- How to 对拍?
对拍从数学的统计学角度来说是一个好的方法,至少能在你竞赛中帮你拿回一些分--yzr大牛pas的对拍一开始还没写过,突然想学一下对拍.那么就学吧.dp水题(搜索):https://www.luogu.o ...
- 【bzoj3237】 Ahoi2013—连通图
http://www.lydsy.com/JudgeOnline/problem.php?id=3237 (题目链接) 题意 给出一个无向图,$Q$组询问,每次询问将原图断掉$C$条边后是否还连通. ...
- python学习(28) 浅谈可变对象的单例模式设计
python开发,有时候需要设计单例模式保证操作的唯一性和安全性.理论上python语言底层实现和C/C++不同,python采取的是引用模式,当一个对象是可变对象,对其修改不会更改引用的指向,当一个 ...
- SqlServer在视图上创建索引
在视图上创建索引需要三个条件: 一.视图必须绑定到架构. 要做到这点,在 CREATE VIEW 语句中,必须加上 WITH SCHEMABINDING,如果是使用企业管理器,则在设计界面的空白处点击 ...
- 【CSS】定义元素的位置
CSS定义元素的位置html元素的position属性,有4个属性值,分别是static.relative.fixed.absolute static: 1.默认值,一般不显式设置为static 2. ...
- spring cloud 微服务架构 简介
Spring Cloud 1. Spring Cloud 简介 Spring Cloud是在Spring Boot的基础上构建的,用于简化分布式系统构建的工具集,为开发人员提供快速建立分布式系统中的 ...
- Windows平台上谷歌浏览器损害电池
From:http://www.cnblogs.com/killerlegend/p/3909208.html Author:KillerLegend Date:2014.8.13 事情是这样的,我的 ...
- 拼接html a标签字符串,onClick传递两个字符串类型参数写法
在参数传递过程中字符串类型的参数要有引号,我一开始拼接的完成后,没有想到要加引号,后来想到了这一问题,可是怎么拼都不对,于是就搜了很多拼接的例子,发现并没有几个能借鉴的,最后终于在一个人的博客中看到, ...
- css 基础2
1.内部样式表: 2.行内样式表:在标签内写style,适合style 比较少的情况 3.外部样式表(外联式): 4.html标签可以分为:块级标签,h1~h6,div ,p,ul,ol,li,div ...
- 《翻译》PEP 380 – 委托子生成器语法
PEP 380 – 委托子生成器语法 翻译自: https://www.python.org/dev/peps/pep-0380/ 摘要 一项新的语法被提出了:生成器委托其部分操作给另一个生成器.委 ...