Java学习总结(二)
5年前
1480
0
Java传参时是引用传递还是值传递,有说Java中只有值传递,也有些地方说引用传递和值传递都存在,本篇记录思考过程,不保证正确性, 感兴趣的同学一起讨论。
Java中数据类型分为两大类,基本类型和对象类型
首先搞清楚 基本类型 和 引用类型的不同之处
int num = 10; String str = "hello";
如图所示,num是基本类型,值就直接保存在变量中,它代表的值就是数值本身。
而str是引用类型,变量中保存的只是实际对象的地址,而不是对象本身。一般称这种变量为"引用",引用指向实际对象,实际对象中保存着内容。
对象本身存放在这个引用值所表示的地址的位置。
基本类型包括:整数、浮点数、字符是基本类型 (byte,short,int,long,char,float,double,Boolean,returnAddress),
引用类型包括:字符串、数组是引用类型(内存数据的索引)
引用传递和值传递
这里要用实际参数和形式参数的概念来帮助理解,
值传递:
方法调用时,实际参数把它的值传递给对应的形式参数,函数接收的是原始值的一个copy,此时内存中存在两个相等的基本类型,即实际参数和形式参数,后面方法中的操作都是对形参这个值的修改,不影响实际参数的值。
引用传递:
也称为传地址。方法调用时,实际参数的引用(地址,而不是参数的值)被传递给方法中相对应的形式参数,函数接收的是原始值的内存地址;
在方法执行中,形参和实参内容相同,指向同一块内存地址,方法执行中对引用的操作将会影响到实际对象。
下面举个例子来帮助理解:
public class Test { public static void main(String[] args) { // 第一种情况传入数组到方法 int[] a = { 1, 2, 3 }; aaa(a,0); for (int i = 0; i < a.length; i++) { System.out.println(a[i]); } // 第二种情况传入字符串 String b = "bbb"; bbb(b); System.out.println(b); // 第三种情况传入整型 int c = 111; ccc(c); System.out.println(c); } public static void aaa(int[] arr, int x){ arr[0] = x; } public static void bbb(String x) { x = "zzz"; } public static void ccc(int x) { x = 222; } }
输出结果是:
0
2
3
bbb
111
第一种情况很好判断,数组的参数传递是引用传递,将内存地址传递到aaa方法,将堆中的arr[0]重新赋值为0。
第二种情况,虽然字符串的参数传递方式是引用传递,但是bbb方法种赋值运算符会改变引用中所保存的地址,即bbb方法中的字符串x的内存地址会被覆盖,但是原来的对象不会被改变,这就是所谓的string不变性。
第三种情况,整型是基本类型,参数传递方式是值传递,将整型c的值赋给方法ccc种的变量x,但是主方法重的c的值没有变化,所以输出的还是111。
String有不变性
String的特点:一旦被赋值,则不能被改变
面试题
String s = new String("Hello")与String s = "hello"的区别?== 比较的是引用类型,是地址值是否相同
equals 比较的是引用类型,默认是比较地址值,而String类重写了equals方法,比较的是内容是否相同。
public class StringDemo3 { public static void main(String[] args) { String s1 =new String("Hello"); //常量池、堆中各新建一个对象,但内存地址不一样 String s2 = "Hello"; //常量池对象已创建,地址指向s1的常量池地址引用 System.out.println(s1==s2); //false System.out.println(s1.equals(s2)); //true } }
结论
1、基本类型参数的传递,是调用方值的复制。双方各自的后续修改,互不影响。
2、引用类型参数的传递,调用方的变量和接收方的参数变量,指向的是同一个对象。双方任意一方对这个对象的修改,都会影响对方。
那么3个例子中,
- 整数的参数传递理解了,复制出来的,分家了,自己管理自己的,类读出数据不变。
- 字符串数组的参数传递也理解了,都是指向同一个地方,数组的一个元素改了,类读出数据也就变了(类一直指向这里)。
- 字符串也是引用参数,为什么类读出数据不变?因为重写了整个字符串(新开内存和指向,参看字符串更改章节),类依然指向之前内存块,类读出数据不变,同结论1。如果只是修改字符串内存中某一个字符的值,则同结论2。
简单总结:类对基本类型是复制数据本身,新开内存。对引用类型是复制指向地址,内存数据本身变化了,类读出数据跟着变化。但字符串修改,是新开内存新指向,已经不能影响类数据。
参考文献: