在网上看了其他一些博主写的,觉得写的不太明了,我来给完善补充一下。
代码语言:javascript复制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);
}
运行的结果是:
代码语言:javascript复制a = 20
b = 10
num1 = 10
num2 = 20
只是把num1,num2的数值拷贝一份交给a,b。a和b做了交换对num1和num2没影响,swap方法结束a和b就销毁了不存在了。这种情况不用多说。
如果需要写交换方法swap().只能用数组,没别的办法
eg:
代码语言:javascript复制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]);
}
}
结果:
代码语言:javascript复制a = 20
b = 10
num1 = 20
num2 = 10
下一个例子:
代码语言:javascript复制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的。(这是同一地址的同一房子里面的操作)
这种情况介绍完毕
下面一种情况:
代码语言:javascript复制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”,所以没有变化。
下一个例子:
代码语言:javascript复制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等这些引用就像一张便利贴,上面只是记载了固定内容的房子(常量池的内容)的地址而已,房子里面东西不能动,如果对房子里面的内容不满意,那就换一个房子。
下一个例子:
代码语言:javascript复制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内容的确被改变了,所以是“我我”。
例子继续:
代码语言:javascript复制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
最后一个例子:
代码语言:javascript复制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,在方法里面操作,方法外面是会变的!!
传递对象,集合的引用,在方法里面操作,方法外面是会变的!!
如果错误或者纰漏之处恳请指正。