Java是值传递还是应用传递

	*最近秋招面试,遇到一道题。Java中是值传递还是应用传递,回来在网上搜了一大圈,查了一些书,有说是值传递的,有说是两者都有的。
	自己整理了一下,再加上自己的理解。**

首先我们要搞清楚什么是值传递和应用传递:
(1)值传递
在方法的调用中,实参会把它的值传递给形参,形参只是用实参的值初始化一个临时的存储单元,因此形参与实参虽然有着相同的值,但是却有着不同的存储单元,因此对形参的改变不会影响实参的值(我在学初学C语言的时候遇到过这种,当时一直都搞不明白)。
(2)引用传递
在方法调用中,传递的是对象(或者说对象的地址),这时形参与实参的对象指向用一块存储单元,此时形参的修改会影响实参的值。
在Java语言中原始数据类型在传递参数时都是按值传递,而包装类型在传递参数时是按引用传递的。
下面通过一个例子来介绍按值传递和按应用传递的区别:

public class Test01 {
    public static void testPassParameter(StringBuffer ss1,int n){
        ss1.append(",world");//引用
        n++;//值
        System.out.println("ss1= " + ss1);
        System.out.println("n=" + n);
    }

    public static void main(String[] args) {
        int i = 1;
        StringBuffer s1 = new StringBuffer("Hello");
        testPassParameter(s1,i);
        System.out.println("s1= " + s1);
        System.out.println("i= " + i);
    }
}

运行结果:
ss1= Hello,world
n=2
s1= Hello,world
i= 1
在这里插入图片描述

上图是值传递与引用传递的过程图,应用传递其实是把对象的地址作为参数的。
简单的说就是假设1和“Hello,world”存储的地址是0X1234567和0XFFFFFF1,在用方法testPassParameter时,由于i为基本类型,因此参数是按值传递的,此时会创建一个副本,该副本与 i 有相同的值,把这个副本作为参数覆给n,作为传递的参数。而StringBuffer由于是一个类,因此按应用传递,传递的是“Hello”所存储的地址,如上图所示,在testPassParameter内部修改的是n的值,这个值与i是没有关系的。但是在修改ss1时,修改的时这个地址指向的字符串,由于形参ss1与实参s1指向的是同一块存储区域,因此修改ss1的值后,s1指向的字符串的值也就被修改了。
可以得出一个结论:Java中处理8中剧本的数据类型用的是值传递,处理其他类型用的是引用传递。那String和它们的包装类呢?我们都知道,String和7种基本数据类型的包装类是一群特殊的群体,在这也不例外。

public class Test02 {
    public static void testString(String str,Integer n){
        str = str + ",world";
        n++;
        System.out.println("str=" + str);
        System.out.println("n=" + n);
    }

    public static void main(String[] args) {
        String st1 = "Hello";
        Integer i = 1;

        testString(st1,i);

        System.out.println("st1=" + st1);
        System.out.println("i=" + i);
    }
}

运行结果:
str=Hello,world
n=2
st1=Hello
i=1
对此,可以得出在Java中基本数据类型以及它们的包装类和String类型是值传递的,而其他类型都是引用传递的,但是有必要理解的一点“引用传递也是按值传递的”。下面给出一个例子说明:

public class Test04 {
    public static void test(StringBuffer ss1, StringBuffer ss2){
        ss1.append(",world");
        ss2 = ss1;
    }

    public static void main(String[] args) {
        StringBuffer s1 = new StringBuffer("Hello");
        StringBuffer s2 = new StringBuffer("Hello");

        test(s1,s2);

        System.out.println("s1=" + s1);
        System.out.println("s2=" + s2);
    }
}

运行结果:
s1=Hello,world
s2=Hello
运行结果出人意料,这时怎么回事呢?假设是s1和s2指向字符串的地址分别为0X1234567和0XFFFFFF1,那么在调用方法test时,就会传递两个地址值,分别为0X1234567和0XFFFFFF1,而且这两个值是按值传递的。因此,在调用方法ss1.append(",world")时,会修改指向ss1所指向的字符串的值,从而修改s1的值。但是在执行到ss2=ss1时,只会修改ss2的值对s2毫无影响。下面给出方法调用的处理过程:
在这里插入图片描述

由上图可以看出,在传递参数时相当于传递了两个地址,在调用ss1.append(",world")时,修改了这个地址所指向的字符串的值,而在调用ss2 = ss1 时,相当于修改了test中局部变量ss2,是与ss1没有关系的。

总结:
(1)在Java中基本数据类型以及它们的包装类和String类型是值传递的,而其他类型都是引用传递的。
(2)引用传递也是按值传递的。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值