在网上看了其他一些博主写的,觉得写的不太明了,或者有些情况没有涉及到甚至有一些小错误,我来给完善补充一下。
public static void main(String[] args) { int num1 = 10; int num2 = 20; swap(num1, num2); System.out.println("num1 = " + num1); System.out.println("num2 = " + num2); } public static void swap(int a, int b) { int temp = a; a = b; b = temp; System.out.println("a = " + a); System.out.println("b = " + b); }
运行的结果是:
a = 20b = 10
num1 = 10
num2 = 20
只是把num1,num2的数值拷贝一份交给a,b。a和b做了交换对num1和num2没影响,swap方法结束a和b就销毁了不存在了。这种情况不用多说。
如果需要写交换方法swap().只能用数组,没别的办法
eg:
public class Test { public static void main(String[] args) { int[] num1 = new int[] {10}; int[] num2 = new int[] {20}; swap(num1, num2); System.out.println("num1 = " + num1[0]); System.out.println("num2 = " + num2[0]); } public static void swap(int[] a, int[] b) { int temp = a[0]; a[0] = b[0]; b[0] = temp; System.out.println("a = " + a[0]); System.out.println("b = " + b[0]); } }
结果:
a = 20
b = 10
num1 = 20
num2 = 10
下一个例子:
public static void main(String[] args) { int[] arr = {1,2,3,4,5}; swap(arr); System.out.println(arr[0]); } //将数组的第一个元素变为0 public static void swap(int[] array) { array[0] = 0; }
输出0
分析:传给swap的是arr引用,通俗易懂的讲就是我传递了一个arr这个房子的地址给array,array有了arr的地址(等于都有了开门钥匙),然后房子里面有5块区域(0,1,2,3,4号区域),然后array把0号区域置为0,swap结束后arr也会发现房子里面的0号区域是0的。(这是同一地址的同一房子里面的操作)
这种情况介绍完毕
下面一种情况:
public static void main(String[] args) { String str = "AAA"; swap(str); System.out.println(str); } public static void swap(String s) { s = "abc"; }
运行结果:AAA
原因:
String的API中有这么一句话:“their values cannot be changed after they are created”,
意思是:String的值在创建之后不能被更改。
API中还有一段:
String str = "abc";
等效于:
char data[] = {'a', 'b', 'c'};
String str = new String(data);
也就是说:对String对象str的任何修改 等同于 重新创建一个对象(比如str = str+"ccc",str就保存的是一个新对象,不是在原有对象进行操作的),并将新的地址值赋值给str。
(所以为了减小额外空间消耗才会经常推荐用StringBuilder和StringBuffer)
传递str给swap方法,传给s,注意了,此刻的s是新的引用,然后将这个引用指向常量池的“abc”,方法结束回到main方法,str仍然指向常量池的“AAA”,所以没有变化。
下一个例子:
public static void main(String[] args) { Double a = 1.0; f(a); System.out.println(a); } public static void swap(Double aa) { aa = 2.0; }
结果显示:1.0
有人疑问了,这种像Double,Integer,Float什么的都是引用啊,改引用为什么不能将这个值改变呢?
a传给f()的是a的地址!!aa保存的是a的地址!也就是常量池里面的数字1.0的地址,然后aa指向了常量池里面2.0的地址,f()结束后a仍然指向1.0的地址没有改变,所以输出1.0。这就是为什么c/c++里面要传二级指针而不是一级指针了,要改变值,必须传一级指针,要改变一级指针指向的地址,必须传二级指针!聪明的你一定知道为什么了。
也就是Double,Integer,Float等这些引用就像一张便利贴,上面只是记载了固定内容的房子(常量池的内容)的地址而已,房子里面东西不能动,如果对房子里面的内容不满意,那就换一个房子。
下一个例子:
class Person { String name; public Person(String name) { this.name = name; } } public class Test { public static void main(String[] args) { Person p = new Person("张三"); change(p); System.out.println(p.name); } public static void change(Person pe) { pe.name = "我我"; } }
结果:我我
此时pe保存的是p传递的引用,也就是地址,person对象是一个有内容的房子,pe有了和p一样的地址(相当于有了同样的开门钥匙),pe对房子里面的name进行了改变,change()方法结束后,p回来发现name内容的确被改变了,所以是“我我”。
例子继续:
class A { public static void change(StringBuilder str) { str.append("def"); } } public class Test { public static void main(String[] args) { StringBuilder sb = new StringBuilder("abc"); A a = new A(); a.change(sb); System.out.println(sb); } }
答案:abcdef
sb传递引用给change()方法,也就是地址,str有了sb的地址,而StringBuilder对象都是在原对象进行操作,不和String一样开辟临时对象,sb这个StringBuilder对象里面保存着abc,然后在change方法里面str也操作的是abc这个对象,直接在后面添加def就行了,最后返回到main,就发现sb变成了abcdef
最后一个例子:
import java.util.HashMap; import java.util.Map; class A { public static void change(Map<String, String> MAP) { MAP.put("key2", "value2"); } } public class Test { public static void main(String[] args) { Map<String, String> map = new HashMap<>(); map.put("key1", "value1"); A a = new A(); a.change(map); System.out.println(map); } }
结果是:{key1=value1, key2=value2}
传递集合的引用和传递对象的引用一样,同一地址房子里面的东西经过一番操作后是会变的
总结:
传递数值给方法,在方法里面操作,方法外面是不变的。
传递String,Integer 、Long、Short、Byte、Character、Double、Float、Boolean、BigInteger、BigDecmail这些引用类型,在方法里面操作,方法外面是不变的!!
传StringBuilder和StringBuffer,在方法里面操作,方法外面是会变的!!
传递对象,集合的引用,在方法里面操作,方法外面是会变的!!
如果错误或者纰漏之处恳请指正。
========================================Talk is cheap, show me the code=======================================