文章目录
前言
今天写代码的时候,犯了一个很基础很低级的错误。实在惭愧,在此花点顺手记录一下,养成习惯。
需求是需要把byte[]作为入参的同时,也作为出参,传一个空白的byte[]作为参数,在方法里面修改byte[],修改完毕后,外面方法获取到被修改后的参数,很简单吧。
失败的修改
new 一个byte[],然后改为全零,再打印看看是否成功:
java
@Test
public void invoke(){
byte[] bytes = new byte[]{1,2,3};
System.out.println("before: bytes = " + Arrays.toString(bytes));
/*changeBytes(bytes);
System.out.println("after changeBytes: bytes = " + Arrays.toString(bytes));*/
changeBytes2(bytes);
System.out.println("after changeBytes2: bytes = " + Arrays.toString(bytes));
}
private void changeBytes2(byte[] bytes) {
System.out.println("changeBytes2 before bytes = " + Arrays.toString(bytes));
bytes = new byte[]{0,0,0};
System.out.println("changeBytes2 after bytes = " + Arrays.toString(bytes));
}
输出:
bash
before: bytes = [1, 2, 3]
changeBytes2 before bytes = [1, 2, 3]
changeBytes2 after bytes = [0, 0, 0]
after changeBytes2: bytes = [1, 2, 3]
可以看到,数组修改失败。
成功的修改
java
@Test
public void invoke(){
byte[] bytes = new byte[]{1,2,3};
System.out.println("before: bytes = " + Arrays.toString(bytes));
changeBytes(bytes);
System.out.println("after changeBytes: bytes = " + Arrays.toString(bytes));
/*changeBytes2(bytes);
System.out.println("after changeBytes2: bytes = " + Arrays.toString(bytes));*/
}
private void changeBytes(byte[] bytes) {
Arrays.fill(bytes, (byte) 0);
}
打印结果:
java
before: bytes = [1, 2, 3]
after changeBytes: bytes = [0, 0, 0]
bytes数据成功被修改。
原理分析
基本类型参数
在 Java 中,传递给方法的参数是按值传递的,这意味着方法得到的是参数的副本,而不是参数本身。对于基本数据类型,这意味着方法得到的是值的拷贝,对参数的修改不会影响调用者的变量。
对象引用参数
但是对于对象引用(包括数组),方法得到的是引用的拷贝,这意味着方法内部可以修改对象的内容,并且这些修改将影响到调用者持有的引用。所以,无论你传递的是数组、集合对象或者是其他对象,只要你在方法内部修改了这个对象的内容,这些修改都会影响到调用者持有的引用。
举一反三:不修改对象参数怎么写?
如果你想要避免对调用者持有的对象产生影响,可以创建一个新的对象,并将修改后的内容复制到新对象中,然后返回这个新对象。这样调用者将得到一个新的对象,原始对象不会受到影响。
举个例子,如果要修改的是一个字符串对象,你可以使用 StringBuilder
类来构建一个新的字符串:
java
private String changeString(String originalString) {
StringBuilder sb = new StringBuilder(originalString);
sb.append(" additional content");
return sb.toString();
}