zoukankan      html  css  js  c++  java
  • java方法传值还是传递引用(系统的分析一下)

    在网上看了其他一些博主写的,觉得写的不太明了,或者有些情况没有涉及到甚至有一些小错误,我来给完善补充一下。

    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 = 20
    b = 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=======================================



    CSDN博客地址:https://blog.csdn.net/qq_34115899
  • 相关阅读:
    关于项目管理的几点建议
    网站性能优化之服务端(一)
    HP CQ35 Windows7声卡驱动安装不上问题
    ubuntu双系统启动时卡死解决办法
    第十九周练习题
    第十六周作业练习题
    第十七周练习题
    第十八周练习题
    第十五周练习题
    第十四周练习题
  • 原文地址:https://www.cnblogs.com/lcy0515/p/9179729.html
Copyright © 2011-2022 走看看