理解JAVA的传值方式

问题: Java的参数传递的是值还是引用?

我们经常会被问到这样的问题,当我调用某个方法时,通过参数传递过去的是变量本身,还是一个变量的复制品?问题的答案留到讨论后给出。
首先,你需要了解下java变量的分类:java中的变量分为
1. 基本类型
2. 接口类型
3. 类类型
4. 数组类型
其中后面三种统称为引用类型,而基本类型分为三种,
1. 数字类型
2. boolean
3. returnAddress
数字类型又分为
1. 浮点类型
2. 整数类型
3. 浮点
整数又有具体的内容,这里不再展开说明。其中,returnAddress是java虚拟机内部使用的类型,它被用来实现java程序中finally子句。这里主要看引用类型和基本类型数字类型情况(boolean类型的情况和基本类型一致).
先看参数为基本类型的情况:

public class Demo1 {
  public void swap(int a, int b) {
    a = a ^ b;
    b = a ^ b;
    a = a ^ b;
    System.out.println("swap: a=" + a + ",b=" + b);
  }
  public static void main(String[] args) {
    Demo1 demo1 = new Demo1();
    int a = 1;
    int b = 2;
    demo1.swap(a, b);
    System.out.println("main: a=" + a + ",b=" + b);
  }
}

输出

swap: a=2,b=1
main: a=1,b=2

上面的代码想通过swap交互a和b的值,在swap内部,变量a和b已经交换成功了,但在main中a和b的值依然是原来的值.
再看参数为引用的情况:

public class ReferenceTest {

    public static void main(String[] args) {
        StringBuffer a = new StringBuffer("A");
        StringBuffer b = new StringBuffer("B");
        swap(a,b);
        System.out.println("a = " + a);
        System.out.println("b = " + b);
    }

    private static void swap( StringBuffer a, StringBuffer b){
        StringBuffer temp = a;
        a = b;
        b = temp;
        System.out.println("a = " + a);
        System.out.println("b = " + b);

    }



}

大家可以先思考下,上面的输出是什么?
输出:

swap: a=b,b=a
main: a=a,b=b

和参数为基本类型的情况结果是一致的.为什么会出现这种情况呢?
我们来分析下上面的参数传递过程,以ReferenceTest为例:
图1是swap未计算前的参数值,

图2是swap计算后的参数值.

java 动态修改返回类型 java返回变量类型_java

从图中可以看出,swap的计算过程只能改变swap内部变量a和b的值,不能改变main中的a和b变量的引用值,换言之,参数的传递只能传值,不存在传引用一说.
请注意,上面我说不能改变a和b变量的引用值,可没说不能改变a和b指向的对象的值.再看下面的例子:

public class ReferenceTest2 {

    public static void main(String[] args) {
        StringBuffer a = new StringBuffer("A");
        StringBuffer b = new StringBuffer("B");
        swap(a,b);
        System.out.println("a = " + a);
        System.out.println("b = " + b);

    }



    private static void swap( StringBuffer a ,StringBuffer b){
        a.append(b);
        StringBuffer temp = a;
        a = b;
        b = temp;
        System.out.println("a = " + a);
        System.out.println("b = " + b);

    }

}

这个会输出什么呢?

swap: a=b,b=ab

swap: a=ab,b=b

这个就是上面所说的,在swap内部的计算过程中,改变了main.a所指向对象的值.

就像下面的图所描述的那样:



但根本上,swap不能改变main中a和b的引用值.

另外贴一句sun公司官方文档上的描述这一问题的原话:

***Java is always pass-by-value.when object is passed as a argument, be careful with that it is also the copy of reference***

所以,现在你应该知道,java传递的只会是值,没有传递引用.

传值和传引用

When you’re passing primitives into a method ,you get a distinct copy of the primitive. When you’re passing a reference into a method , you get a copy of the reference.
以上引自《Thinging in Java》,总结一下就是不管Java参数的类型是什么,一律传递参数的副本。
在Java中,变量分为以下两类:
1. 对于基本类型变量(int、long、double、float、byte、boolean、char),Java是传值的副本。
2. 对于一切对象型变量,Java都是传引用的副本,其实穿引用副本的实质就是复制指向地址的指针。