深入理解--Java按值传递和按引用传递

引言

最近刷牛客网上的题目时碰到不少有关Java按值传递和按引用传递的问题,这种题目就是坑呀,在做错了n次之后,查找了多方资料进行总结既可以让自己在总结中得到提高,又可以让其他人少走弯路。何乐而不为?

Java按值传递和按引用传递

首先问一句:Is Java “pass-by-reference” or “pass-by-value”? Java到底是按值传递还是按引用传递的呢?国外的网站上关于这个问题的讨论非常之多。官方答案:The Java Spec says that everything in Java is pass-by-value. There is no such thing as “pass-by-reference” in Java. 官方的说法是在java中只有按值传递,并没有所谓的按引用传递。

基本数据类型的按值传递

java数据类型可以分为两大类:基本类型(primitive types)和引用类型(reference types)。primitive types 包括boolean类型以及数值类型(numeric types)。numeric types又分为整型(integer types)和浮点型(floating-point type)。整型有5种:byte short int long char(char本质上是一种特殊的int)。浮点类型有float和double。关系整理一下如下图:

这里写图片描述
例1

public class Swap {

    public static void main(String[] args) {
        int x = 10;
        int y = 20;
        swap(x, y);
        System.out.println("x(2) = " + x);
        System.out.println("y(2) = " + y);
    }
     public static void swap(int x, int y) {
        int temp = x;
        x = y;
        y = temp;
        System.out.println("x(1) = " + x);
        System.out.println("y(1) = " + y);
    }
}

    /*输出
    x(1) = 20
    y(1) = 10
    x(2) = 10
    y(2) = 20
    */

上面程序main函数调用swap函数来交换 x,y的值,然而调用函数之后发现main中x,y的值并未交换。包括在Java api中找不到一个可以交换两个变量的方法。这与Java语言的特性有关。通过一个图就可以知道上面程序的运行结果了。

这里写图片描述
由上图可知,main函数中的x,y和swap函数中的x,y分别存放在不同的区域,在main中调用swap函数的时候,会将main中的x,y的值赋给swap中的x,y。当swap函数中对x,y交换时只是对swap帧中的x,y做交换,并不会改变main中的x,y。所以当函数返回时main中的x,y并不会改变。swap执行过程图如下:
这里写图片描述

对于基本数据类型 short int long float double char byte boolean这八种按值传递调用函数并不会改变在原函数中的值。

引用数据类型的按值传递

引用数据数据类型分为三种:①接口 ②类 ③数组对于引用数据类型的按值传递先给出一个实例对比实例进行分析。

例2

public static void main(String[] args) {    
        int []a={10,20};
        System.out.println("a[0] :"a[0]+"a[1] : "+a[1]);//a[0]=10,a[1]=20;      
        swap(a, 0, 1);
        System.out.println("a[0] :"a[0]+"a[1] : "+a[1]);//a[0]=20,a[1]=10;  

    }
public static void swap(int []a,int i,int j){
        int temp=a[i];
        a[i]=a[j];
        a[j]=temp;
        System.out.println("a[0] :"a[0]+"a[1] : "+a[1]);//a[0]=20,a[1]=10;
    }
//输出
/*a[0]=10 a[1]=20

  a[0]=20 a[1]=10

  a[0]=20 a[1]=10   
*/

运行程序后发现,swap函数对a[0] ,a[1]的操作竟然影响到了main函数中的a[0] ,a[1]的值,真是不可思议。为什么会产生如此之结果。原来引用类型的按值传递,传递的是对象的地址。还是用图来解释一下。

这里写图片描述
由图可以看出在swap中仅仅是得到了数组的地址,并没有对数组的元素进行复制,在swap中对数组的操作是直接对main函数中数组的操作,因此swap函数返回后main函数中的a[0] ,a[1]的值发生交换。

数组、类、接口按值传递的时候都是传递对象的地址。再来看一个比较复杂的实例。

例3

public class Main{
     public static void main(String[] args){
          Foo f = new Foo("f");
          changeReference(f); // It won't change the reference!
          modifyReference(f); // It will modify the object that the reference variable "f" refers to!
     }
     public static void changeReference(Foo a){
          Foo b = new Foo("b");
          a = b;
     }
     public static void modifyReference(Foo c){
          c.setAttribute("c");
     }
}

①Foo f = new Foo(“f”);
这里写图片描述

②public static void changeReference(Foo a)
这里写图片描述

③changeReference(f);
这里写图片描述

④Foo b = new Foo(“b”);
enter image description here
⑤a = b
enter image description here

enter image description here
⑥c.setAttribute(“c”);

enter image description here

经典笔试题目

试题1

public class Demo {

    public static void main(String[] args) {

        //demo1
        String str=new String("hello");
        char []chs={'w','o','r','l','d'};
        change(str, chs);
        System.out.println(str+" "+new String(chs));

        //-------------------------------------------------
        //demo2

        StringBuffer sb=new StringBuffer("hello");
        change(sb);
        System.out.println(sb);

    }
    public static void change(StringBuffer sb)
    {
        sb.append(" world");
//      sb.deleteCharAt(0);
    }
    public static void change(String str,char[]chs)
    {
        str.replace('h', 'H');
        chs[0]='W';     
    }       
}

上面程序段demo1和demo2分别输出什么,这里涉及到String特性,这道题目会做了,Java按值传递和按引用传递就彻底懂了,答案和解析先匿了。

试题2

public class foo {
    public static void main(String sgf[]) {

        StringBuffer a=new StringBuffer(“A”);
        StringBuffer b=new StringBuffer(“B”);
        operate(a,b);
        System.out.println(a+”.”+b);

    }

    static void operate(StringBuffer x,StringBuffer y) {

        x.append(y);
        y=x;

    }
}

参考文献

1.https://stackoverflow.com/questions/40480/is-java-pass-by-reference-or-pass-by-value

已标记关键词 清除标记
©️2020 CSDN 皮肤主题: Age of Ai 设计师:meimeiellie 返回首页