一个问题:
import java.util.ArrayList;
import java.util.List;
/**
* 一个列表中存放了一些String,这个时候需要将里面的String长度超过15的给去掉
* 利用一个void的方法来进行操作,我们看下下面的结果
*/
public class TestStr
{
public static void main(String[] args)
{
List<String> l = new ArrayList<String>();
l.add("abc");
l.add("abc");
l.add("abcdefghijklmnopqrstuvw");
l.add("abcdefghijklmnopqrstuvw");
l.add(null);
l.add(null);
TestStr.doList(l);
for(String str : l)
{
System.out.println(str);
}
TestStr.doList(l);
System.out.println();
for(String str : l)
{
System.out.println(str);
}
}
public static void doList(List<String> list)
{
//将List里面的String长度超过15的放到一个新的列表里面
List<String> l1 = new ArrayList<String>();
for(String str : list)
{
if( str == null || str.length() < 15 )
{
l1.add(str);
}
}
//将当前列表指向新建的列表
list = l1;
}
}
打印的结果是
结果
abc
abc
abcdefghijklmnopqrstuvw
abcdefghijklmnopqrstuvw
null
null
abc
abc
abcdefghijklmnopqrstuvw
abcdefghijklmnopqrstuvw
null
null
abc
abcdefghijklmnopqrstuvw
abcdefghijklmnopqrstuvw
null
null
abc
abc
abcdefghijklmnopqrstuvw
abcdefghijklmnopqrstuvw
null
null
这是为什么?
这是因为,在main方法向doList方法传参数的时候,是将【l】指向的地址传给了doList方法里面的参数【list】,这个时候doList的参数的引用【list】指向main方法里面l的地址,如果这个时候直接在【list】上面修改,则会改变main方法里面【l】的列表,但是在doList并不是这么做,而是以为doList方法里面的【list】就是main方法里面的【l】,这个时候改变【list】的引用,其实只是修改了参数的引用地址,而main方法里面的地址其实没有改变。依然指向原先的位置。
下面贴出正确的代码:
import java.util.ArrayList;
import java.util.List;
public class Test
{
public static void main(String[] args)
{
List<String> list1 = new ArrayList<String>();
list1.add(null);
list1.add("");
list1.add(null);
list1.add("");
list1.add("aaa");
list1.add("aaa");
list1.add("abcdefghijklmnopqrst");
list1.add("abcdefghijklmnopqrst");
System.out.println("Before doList");
for(int i = 0; i <list1.size();i++ )
{
Test.p(list1.get(i));
}
Test.doList(list1);
System.out.println("\nAfter doList");
for(int i = 0; i <list1.size();i++ )
{
Test.p(list1.get(i));
}
}
public static void doList(List<String> list)
{
System.out.println("\nIn doList");
for(int i = list.size(); i >= 1 ;i-- )
{
if(list.get(i-1) != null && list.get(i-1).length() >= 15)
{
System.out.print("the " + i +"th Element " + "is " +list.get(i-1)+'\n');
list.remove(i-1);
}
}
}
public static void p(Object o)
{
System.out.println(o);;
}
}
结果 写道
Before doList
null
null
aaa
aaa
abcdefghijklmnopqrst
abcdefghijklmnopqrst
In doList
the 8th Element is abcdefghijklmnopqrst
the 7th Element is abcdefghijklmnopqrst
After doList
null
null
aaa
aaa
null
null
aaa
aaa
abcdefghijklmnopqrst
abcdefghijklmnopqrst
In doList
the 8th Element is abcdefghijklmnopqrst
the 7th Element is abcdefghijklmnopqrst
After doList
null
null
aaa
aaa
一个更容易理解的例子
public class Test2
{
public static void main(String[] args)
{
Person person = new Person();
change(person);
System.out.println(person);
}
/**
* 这里其实也是传递的副本
* 当你调用change时,外部传入的person有一个内存地址指向创建的对象,同时change方法内也创了一个副本地址指向同一个对象
* 此时你用副本对象去进行add,remove,set等操作都是有效的
* 但你对副本对象引用进行赋值操作,此时副本对象指向另一个地址,而原传进来的引用还是指向原地址,所以赋值不起作用
*
* */
public static void change(Person person)
{
person.setName("yy");
person.setAge(28);
Person p1 = new Person();
p1.setAge(16);
p1.setName("xx");
person = p1;
}
}
class Person
{
private String name;
private int age;
public String getName()
{
return name;
}
public void setName(String name)
{
this.name = name;
}
public int getAge()
{
return age;
}
public void setAge(int age)
{
this.age = age;
}
public String toString()
{
return "age = " + this.age + ",name = " + this.name;
}
}
结果
age = 28,name = yy