zoukankan      html  css  js  c++  java
  • 【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:1 1 1 
    after:2 2 1 
    View Code

       上面的代码可以知道,存储Person这个对象时(存储的是地址),b和a其实是同一个地址,所以a指向的对象改变,会引起链表中的前两个结点(地址相同)改变,而如果要使存进链表的person存储的是a存储时的状态,只能新建一个对象c,令c的内容等于a,才在后面不会发生变化(因为该地址指向的内容没有再发生改变了)。

       关于String的讨论:其实String也是对象,存储的其实也是引用(地址),但为什么上面代码中before和after输出的内容都是“abc”呢?其实在aString="123";时,相当于aString=new String("123"),即aString指向了另一个对象,aString存储的地址变成了“123”的地址,但链表中存储的还是“abc”的地址,所以链表中的内容不变。

      更详细的传递讨论:值传递和引用传递讨论

  • 相关阅读:
    【整理】PHP获取客户端真实IP地址详解
    配置百度编辑器变成纯代码编辑器
    Notepad++安装SVN插件
    【CodeBase】【转】php随机生成汉字
    【CodeBase】PHP打印所有用户自定义常量
    php5.3新垃圾回收机制详解
    php脚本cli 模式运行
    php 内存分配新
    php-fpm epoll封装
    火焰图定位dbproxy问题
  • 原文地址:https://www.cnblogs.com/yongh/p/9821916.html
Copyright © 2011-2022 走看看