ArrayList修改“get”方法返回的值

时间:2015-03-18 09:57:44

标签: java android arraylist

我有以下两种与ArrayList get方法相关的情况,一种是自定义类,另一种是String类:

1。下面是修改Custom class ArrayList元素的示例:

ArrayList<MyClass> mTmpArray1 = new ArrayList<MyClass>();
MyClass myObj1 = new MyClass(10);  
mTmpArray1.add(myObj1);

MyClass myObj2 = mTmpArray1.get(0);  
myObj2.myInt = 20;

MyClass myObj3 = mTmpArray1.get(0);  
Log.d(TAG, "Int Value:"+myObj3.myInt);    // Prints "20" 

2。以下是修改String ArrayList元素的示例:

ArrayList<String> mTmpArray2 = new ArrayList<String>();  
mTmpArray2.add("Test_10");

String myStr1 = mTmpArray2.get(0);
myStr1 = "Test_20";

String myStr2 = mTmpArray2.get(0);
Log.d(TAG, "Str Value:"+myStr2);  // Prints "Test_10" 

因此,在MyClass ArrayList的情况下,当我调用get并修改值时,我看到当我再次get时,更改正在反映。

但是当我修改String ArrayList时,改变并没有反映出来。

两种情景中get方法的不同之处是什么?
是在String的情况下,String类创建深层副本并返回新对象,并且在Custom类的情况下创建浅层副本?

在适用于“LinkedHashMap”,“HashMap”和“List”的第一个场景中?

6 个答案:

答案 0 :(得分:3)

在这两种情况下你没有做同样的事情。

在此更新对象的状态,因此更改会影响列表中存储的对象:

myObj2.myInt = 20;

在这里,您要为局部变量分配一个新对象,因此列表不受影响:

myStr1 = "Test_20";

如果String是可变的,您可以通过调用某个方法修改String,并且更改将反映在列表中存储的对象中:

myStr1.setSomething(...);

另一方面,如果在第一种情况下您将更改局部变量的值,则列表中存储的对象不会受到影响:

myObj2 = new MyClass (...);

答案 1 :(得分:2)

字符串是不可变的。您没有将新字符串插入数组列表。

当你执行String myStr2 = mTmpArray2.get(0);时,即使你指向ArrayList中的引用,任何改变值的尝试都会(因为String immutability)会创建一个不会引用它的新String(myStr2) ArrayList了。

执行myStr1 = "xxx"时,您实际上并没有更改ArrayList引用,而是要更改从ArrayList中获取的新(副本)(现在称为myStr1)并且它具有当地范围。

详细了解字符串:Immutability of Strings in Java

现在在第一个示例中,您指向一个可变对象(您的自定义类),因此您可以通过引用直接更改直接值。欢迎来到Java。 ;)

无关:此代码:MyClass myObj1 = new MyClass(10);(可以说)被认为是错误的。最好使用更容易阅读的 factory 模式。换句话说,带参数的公共构造函数很难阅读(例如,当我读取代码时,我不知道我在构建什么)。

(或许)更好的方法是:MyClass myObj = MyClass.createInstanceWithCapacity(10); // i've invented the name because I don't know what your 10 is, but look at both, which one do you think is easier to understand upon first glance?

免责声明:以上不相关的评论是我个人的观点,并非所有开发者都会同意。 ;)

答案 2 :(得分:1)

字符串具有非常好的属性,称为“Immutablity”

  

这意味着当我们创建/时,String不能是可变的(已更改)   尝试引用旧字符串,创建一个新的实例字符串。而且任何   我们所做的更改将保存在新实例中,并且不会影响旧实例   串

例如,

String s = "Old String";
System.out.println("Old String : "+s); // output : Old String

String s2 = s;
s2 = s2.concat(" made New");
System.out.println("New String : "+s2); // output : Old String made New
System.out.println("Old String is not changed : "+s); // output : Old String

答案 3 :(得分:0)

这两者之间没有区别&#34;得到&#34;调用。不同之处在于ArrayList所持有的类型,以及您正在进行的引用&#34; get&#34;方法返回。

在您的第一个示例中,您执行此操作:

MyClass myObj2 = mTmpArray1.get(0);  
myObj2.myInt = 20;

在这里,您在位置0的ArrayList中获取对MyClass实例的引用,并且您正在修改此实例中的字段。

在你的第二个例子中,你这样做:

String myStr1 = mTmpArray2.get(0);
myStr1 = "Test_20";

在这里,您将获得对数组列表中String实例的引用,然后您为myStr1提供对您创建的其他字符串的引用(&#34; Test_20&#34;) 。就像你在第一个例子的第二行写了myObj2 = new MyClass(20);一样。

因此,简而言之,在第一个示例中,您可以通过从您抓取的引用中更改对象来访问对象中的字段。在第二个示例中,您只需将引用更改为指向不同的String。

我还应该提到,在Java中,字符串是不可变的,这意味着一旦创建它们就无法更改。

答案 4 :(得分:0)

String是一个不可变的类。像

这样的一行
myStr1 = "Test_20";

不会更改指向的myStr1字符串对象的值。而是创建一个新的String,并修改myStr1以指向新的String。原始String保持不变,可以从ArrayList中检索。

您的MyClass对象显然是可变的。只创建一个实例,并通过赋值更改其状态

myObj2.myInt = 20;

因此,当从ArrayList检索此对象时,会看到其新状态。

答案 5 :(得分:0)

您只是不要在第二个示例中更改列表。

在第一个例子中,您正在执行此操作:

  1. 从列表中获取第一个对象并将其存储在名为“myObj2”
  2. 的变量中
  3. 通过设置此对象的int值
  4. 来修改存储在变量'myObj2'中的对象

    但你的第二个例子完全不同:

    String myStr1 = mTmpArray2.get(0);
    myStr1 = "Test_20";
    

    让我翻译一下:

    1. 从列表中获取第一个元素并将其存储在名为“myStr1”的变量中。
    2. 将变量'myStr1'的值设置为“Test_20”
    3. 因此,如果您正在修改列表中存储的对象的变量。在第二种情况下,您正在检索存储在列表中的对象 - 然后重新使用您存储检索到的对象的变量并将其用于新的 - 但这当然不会改变原始列表。

      要修改类似字符串的类型列表,您需要使用set(x,“Test_20”)。