今天在公司做的一个订购成功后发送给用户的邮件时,见到了之前别人留下来的一个问题。类似于下面这样的代码:
public class Test {
public static void test(List<Person> persons) {
Map<String,Person> map = new HashMap<>();
//把name相同的person合并,age相加
for (Person person : persons) {
if(map.containsKey(person.getName())) {
Person person1 = map.get(person.getName());
person1.setAge(person.getAge() + person1.getAge());
} else {
map.put(person.getName(),person);
}
}
Collection<Person> values = map.values();
//这个persons指向新new的一个对象
persons = new ArrayList<>(values);
System.out.println(persons.toString());//-->[Person{name='s1', age='8'}]
}
public static void main(String[] args){
ArrayList<Person> persons = new ArrayList<>();
persons.add(new Person("s1",5));
persons.add(new Person("s1",3));
test(persons);
System.out.println(persons);//-->[Person{name='s1', age='8'}, Person{name='s1', age='3'}]
}
}
- main函数中外部有一个persons对象,传入test函数中,test函数中又把persons指向了一个新的对象,for循环中直接操作了persons中的对象。看下代码中的输出,persons的打印方法内外不一样。
下面的例子清晰点:
public class Test2 {
public static void setValue(String str){
str = "ss";
}
public static void setValue(Man str){
str = new Man("test");
}
public static class Man{
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Man(String name) {
this.name = name;
}
@Override
public String toString() {
return "Man{" +
"name='" + name + '\'' +
'}';
}
}
public static void main(String[] args) {
String str = "s";
setValue(str);
System.out.println(str);
Man man = null;
setValue(man);
System.out.println(man);
}
}
上面代码输出:
s
null
原因是方法在执行的时候有栈帧的概念,入栈的时候只是压栈,方法参数是传入参数的副本。
基本类型:值存放在局部变量表中,无论如何修改只会修改当前栈帧的值,方法执行结束对方法外不会做任何改变;此时需要改变外层的变量,必须返回主动赋值。
引用数据类型:指针存放在局部变量表中,调用方法的时候,副本引用压栈,赋值仅改变副本的引用。但是如果直接改变副本引用的值,修改了引用地址的对象,此时方法以外的引用此地址对象当然被修改。(两个引用,同一个地址,任何修改行为2个引用同时生效)
比如
public static void setValue(StringBuilder str){
str = new StringBuilder("sss");
}
public static void setValue2(StringBuilder str){
str.append("sss");
}
public static void main(String[] args) {
StringBuilder str = new StringBuilder();
setValue(str);
System.out.println(str.toString()); //输出空字符串
setValue2(str);
System.out.println(str.toString()); //输出sss
}
关于String,本质是final类型char数组,不可修改,只能赋值,在做参数传入方法修改时,其实是新建对象,必须返回重新对外面的变量赋值才会对外面的String引用生效。
原文链接:https://blog.csdn.net/fenglllle/article/details/81389286
网友评论