java方法传值还是传递引用(系统的分析一下)

2023-05-06 17:11:54 浏览数 (1)

在网上看了其他一些博主写的,觉得写的不太明了,我来给完善补充一下。

代码语言: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,在方法里面操作,方法外面是会变的!!

传递对象,集合的引用,在方法里面操作,方法外面是会变的!!

如果错误或者纰漏之处恳请指正。

0 人点赞