疯狂java


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

Java中的值传递与“引用传递”


 

  首先,Java没有 引用传递 这么一说。

  Java只有值传递,传递的都是值,基本数据类型传递的是值,引用类型传递的是地址值。

  我来理一下这其中犹如米线跟米面绞在一起了,再跟粉丝混在一起的关系。

  好的,我们来看第一个例子:

  public static void main(String[] args) {

  int a = 1;

  int b = 4;

  System.out.println("Before : a=" + a + "," + "b=" + b);

  swap(a, b);

  System.out.println("After : a=" + a + "," + "b=" + b);

  }

  private static void swap(int a, int b) {

  int temp = a;

  a = b;

  b = temp;

  }

  结果:

  Before : a=1,b=4

  After : a=1,b=4

  这没什么好说的,main函数内的a和b 与 swap()函数中的a,b半毛线关系都没有,交换的只是swap函数中的局部变量,并不会影响到main函数中的a和b.

  2,第二个:

  public static void main(String[] args) {

  Integer a = new Integer(3);

  Integer b = new Integer(4);

  System.out.println("Before : a = " + a + " b = " + b);

  swap(a, b);

  System.out.println("After : a = " + a + " b = " + b);

  }

  public static void swap(Integer a1, Integer b1) {

  Integer temp = a1;

  a1 = b1;

  b1 = temp;

  }

  结果:

  Before : a = 3 b = 4

  After : a = 3 b = 4

  很多人可能会惊讶,为什么会介个样子的呢?为什么 还是木有交换呢。

  1,a将引用值传给a1,b将引用值传给b1,此时a1和a都指向3的空间,b1和b都指向4的空间

  2,在swap函数中,a1和b1的引用值,注意是引用值!此时a1指向4,b1指向3

  3,再看看打印语句:

  System.out.println("After : a = " + a + " b = " + b);

  打印的是a 和 b 的值,跟a1,b1又有什么关系呢?交换的只是a1和b1的引用值,说白了a1,b1就是a,b的引用副本,这里有四个引用指向了2个地址空间。交换了其中的两个,并不影响其他两个引用的值。

  好,说完了上面这么多。我们再来看一个例子:

  首先自定义一个类:

  public class Person {

  private int age;

  public int getAge() {

  return age;

  }

  public void setAge(int age) {

  this.age = age;

  }

  }

  public static void main(String[] args) {

  Person p = new Person();

  System.out.println("Before : "+p.getAge());

  changePersonAge(p);

  System.out.println("After : " + p.getAge());

  }

  public static void changePersonAge(Person p) {

  p.setAge(10);

  }

  结果:

  Before : 0

  After : 10

  是不是很神奇,这里竟然又可以改变值啦。

  注意:这里p将引用副本传递给changePersonAge()函数,同样此时存在两个引用指向堆空间中的Person对象。那么在changePersonAge()方法中调用setAge()函数,实质改变的也就是Person对象中age的值,这里改变的是对象,而不是单纯的引用值的传递。

  我们再来看一个例子:

  public static void main(String[] args) {

  String str = "test";

  System.out.println("Before = "+str);

  changeStr(str);

  System.out.println("After = " + str);

  }

  public static void changeStr(String str) {

  str += "haha";

  }

  结果:

  Before = test

  After = test

  哎哟我去,咋又不能改变了呢?

  在main方法里str首先指向常量池中的“test”,而后将引用副本传递给changeStr方法中的str,同样这里存在两个引用,但是在changeStr方法里做出了,str+="haha";的操作,注意,此时changeStr中的str不再指向“test”,而是指向了“testhaha”,两个引用指向了不同的空间,打印出来当然没有改变值咯。

  最后,我们再来看一个小例子,稳固一下。

  public static void main(String[] args) {

  StringBuffer sb = new StringBuffer("test2");

  System.out.println("Before = " + sb);

  changeStr(sb);

  System.out.println("After = " + sb);

  }

  private static void changeStr(StringBuffer sb) {

  sb.append("haha");

  }

  结果:

  Before = test2

  After = test2haha

  这里改变了值,已经引起不了大家的大惊小怪了,实质上跟上面的Person对象例子是类似的。

  sb将引用副本传递给changeStr方法,再在changeStr方法中调用append方法,实质上是在改变两个引用共同指向的空间的值,不是引用传递也不是引用指向了别的空间。