疯狂java


您现在的位置: 疯狂软件 >> 新闻资讯 >> 正文

java的引用传递和值传递


 

   java的引用传递和值传递

  先来看一段代码的执行结果。

  A.java

  public class A {

  private String mText;

  public A(String text) {

  mText = text;

  }

  @Override

  public String toString() {

  return mText;

  }

  }

  Main.java

  public class Main {

  public static void main(String[] args) {

  A a1 = new A("a1");

  A a2 = new A("a2");

  System.out.println("a1:" + a1 + " | a2:" + a2);//[1]

  swap(a1, a2);

  System.out.println("a1:" + a1 + " | a2:" + a2);//[3]

  }

  private static void swap(A one, A another) {

  A tmp = one;

  one = another;

  another = tmp;

  System.out.println("one:" + one + " | another:" + another);//[2]

  }

  }

  位置[1]会打印:a1:a1 | a2:a2

  位置[2]会打印:one:a2 | another:a1

  位置[3]会打印:a1:a1 | a2:a2

  咦?好像有哪里不对,为什么位置[3]会打印a1a2,而不是a2a1呢,在swap()中不是交换过对象了吗?

  现在分析一下整个过程:

  位置[1]

  a1、a2分别指向两个不同的对象,每个对象通过构造函数赋予不同的值来区分,所以在位置[1]打印的结果是显而易见的。”a1:a1 a2:a2”

  位置[2]

  在swap()中,

  1. 因为A是一个类,所以参数是引用传递的,那么one是a1的别名,another是a2的别名。

  2. one和another在交换值之后,one指向a2的地址,another指向了a1的地址。

  所以,最后打印结果是交换过的。

  位置[3]

  因为是引用传递,one是a1的别名,another是a2的别名,one和a1、another和a2就是一个东西,在swap中把one和another交换值,就相当于把a1和a2交换了值。

  那么最后打印的结果应该是“a1:a2 | a2:a1”

  但是实际打印结果和分析的结果是相反。为什么呢?

  上述的分析过程是没有错的,那么出问题的地方在哪里?

  真相是——第一步就出问题了,整个的分析过程是在参数引用传递这个概念的基础上进行的,前提条件错了,后面的分析结果也必然是有问题的。

  事实是,在java中只有值传递,没有引用传递。

  那么从头再按照值传递的观点分析一下整个过程。

  位置[1]

  a1、a2分别指向两个不同的对象,a1、a2保存的是两个对象的地址,每个对象通过构造函数赋予不同的值来区分,所以在位置[1]打印的结果是显而易见的。”a1:a1 a2:a2”

  位置[2]

  在swap()中,

  1. 因为A是一个类,参数值传递的是对象的地址,那么one保存的是a1的地址,another保存的是a2的地址。

  2. one和another在交换值之后,one保存了a2的地址,another保存了a1的地址。

  所以,打印one和another的结果是交换过的。

  位置[3]

  因为参数是值传递,one和another在参数传递的时候,只是获取了a1、a2保存的值的拷贝,one和another的交换和a1、a2没有任何关系,从而不会导致a1、a2变化,所以再次打印a1、a2的时候,结果仍然是“a1:a1 | a2:a2”