Java基础-值传递

前言:今天帮同事处理了一个问题,这是一个关于JAVA值传递问题,自己刚好回顾记录一下
  1. 整体的逻辑大概类似于如下的代码
public void test() {
	Map<String,String> tempMap = new HashMap<>(8);
	List<Map> resultList = new ArrayList<>();
	for (int i = 0; i < 2; i++) {
		tempMap.put("key1" + i,"value");
		resultList.add(tempMap);
		System.out.println(resultList);
	}
	System.out.println(resultList);
}

输出的结果如下

[{key10=value}]
[{key11=value, key10=value}, {key11=value, key10=value}]
[{key11=value, key10=value}, {key11=value, key10=value}]

看到这个结果,我相信你的第一个感觉是嗯?,然后很快就是嗯!了,这是一个典型的Java值传递的问题
2. 关于传递的例子

public class Deal {

    public static void main(String[] args) {
        int a = 10000;
        addOne(a);
        addTwo(a);
        String s = "abc";
        addOneString(s);
        addTwoString(s);
        StringBuffer sb = new StringBuffer("abc");
        addOneStringBuffer(sb);
        addTwoStringBuffer(sb);
    }

    public static void addOne(int a) {
        System.out.println("执行前addOne后a的值为:" + a);
        a += 1;
        System.out.println("执行后addOne后a的值为:" + a);
    }

    public static void addTwo(int a) {
        System.out.println("执行前addTwo后a的值为:" + a);
        a += 1;
        System.out.println("执行后addTwo后a的值为:" + a);
    }

    public static void addOneString(String s) {
        s += "d";
        System.out.println("执行完addOneString后a的值为:" + s);
    }

    public static void addTwoString(String s) {
        s += "e";
        System.out.println("执行完addTwoString后a的值为:" + s);
    }

    public static void addOneStringBuffer(StringBuffer a) {
        a.append("d");
        System.out.println("执行完addOneStringBuffer后a的值为:" + a);
    }

    public static void addTwoStringBuffer(StringBuffer a) {
        a.append("e");
        System.out.println("执行完addTwoStringBuffer后a的值为:" + a);
    }
}

运行结果

执行前addOne后a的值为:10000
执行后addOne后a的值为:10001
执行前addTwo后a的值为:10000
执行后addTwo后a的值为:10001
执行完addOneString后a的值为:abcd
执行完addTwoString后a的值为:abce
执行完addOneStringBuffer后a的值为:abcd
执行完addTwoStringBuffer后a的值为:abcde

首先说对于基本类型和引用类型,传递都是值传递,只有值传递。对于基本类型传递过去的的是值的拷贝,引用类型传递过去的是对应的堆中的地址的拷贝。,分析addTwo调用前输出,可以知道对于基本类型int来说,传递给方法addTwo的参数a是把a的值传递过去,每一次传递都是把当前的值传递过去,所以在计算结果的时候,数据没有出现累加的情况;而对于字符串类型String来说,传递给方法addTwoString的是字符串 "abc"的引用地址的值这里定义为001,然后调用addTwoString后new了一个新的对象,这个对象的地址是002,这个时候当前方法内的s的值是002,指向了新new出来的对象,对外部的对象没有任何的影响;对于addTwoStringBuffer可以看出在调用addTwoStringBuffer的时候传递过去的引用地址的值,在处理过程中这个引用的地址的值没有变化,但是引用地址指向的堆中的内容发生了变化,所以方法执行完以后对外部的变量产生了影响

  1. 问题:StringStringBuffer都属于字符串类型,为什么结果不一样呢
    这里我把s += "d"换为s = s.concat("d"),观察执行结果,发现是一样的,查看concat的源码
public String concat(String str) {
        int otherLen = str.length();
        if (otherLen == 0) {
            return this;
        }
        int len = value.length;
        char buf[] = Arrays.copyOf(value, len + otherLen);
        str.getChars(buf, len);
        return new String(buf, true);
}

对比append的源码

public synchronized StringBuffer append(String str) {
	toStringCache = null;
	super.append(str);
	return this;
}

可以看到concat返回的是一个new出来的新的对象,这样,而append返回的确是当前的对象,这就可以得出一个结论,每次对String进行操作的时候结果都是一个新的对象,对StringBuffer进行类似append,delete,deleteCharAt,replace…的操作结果都是当前对象

PS: 平时同事碰到问题喜欢找我来解决,一般我的时间有限,我不会去整体了解问题,我只是抓住他们认为非常诡异的点,想想会有什么问题,提出自己的方案。就像这个问题,前后的逻辑大概有500行的代码,我过去后同事拿出要把整个逻辑都给我讲一件的架势,我立刻说先给我看看结果,对着结果给我说一说有什么问题,抓住关键点我一步一步的问了问题,前后也就五分钟就找到问题点,最开始真没有想到是这么基本的问题。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值