日期:2014-05-20  浏览次数:20760 次

几点疑问,坐等大神解惑
package org.bruce.foundation.test;

public class TestXX {

public static void main(String args[]) {
Boolean bValue = new Boolean(false);
String str = new String("false");
Integer integer = Integer.valueOf(3);

change(bValue);
System.out.println(bValue);

change(str);
System.out.println(str);

change(integer);
System.out.println(integer);
}

public static void change(Integer integer) {
++ integer;
}

public static void change(Boolean bValue) {
bValue = new Boolean(true);
}

public static void change(String str) {
str = "true";
}
}

执行结果是什么?为什么会有那样的结果呢?
java

------解决方案--------------------
世界上所有的编程语言都只有值传递,所谓的“引用传递”,其底层实现依然是值传递。以 change(String str),Integer、Boolean用同样的思路去考虑:
1、当执行第七行
String str = new String("false");

的时候,内存是这样的:


2、当调用第28行的 change(String str)函数时:
public static void change(String str) {
        str = "true";
    }

内存如下所示,栈内存的特点是“由高向低扩展,且连续,复杂度为O(1),速度仅次于寄存器”,而堆内存的特点是“由低向高扩展,总是寻找静态链表中的闲置区域,复杂度为O(N),所以比栈内存慢,且不一定连续”:

3、当change(String str)函数执行完毕,函数执行到14行的时候:
System.out.println(str);

change(String str)中的str将被立即回收,new String("true")已经没有引用指向它,gc线程的“引用计数收集器”会找机会回收它,但不一定立即回收,因为main线程可能正在run.

可以用同样的思路去理解Boolean、Integer、Person,在研究面向过程、面向对象的同时,不要忘了去“面向内存”,甚至可以像@zhao4zhong1一样,去“面向汇编”、“面向二进制”。
这就同时解释了一个常见的面试题“String、StringBuffer的异同”,StringBuffer的实现类似于ArrayList,是一个可扩充的char[],在进行扩充的时候,执行了“申请新数组、释放旧数组”两个操作;而String在静态区所占的内存在整个程序中都不会被释放,所以频繁调用"+"运算符,造成效率低下。
------解决方案--------------------
假设调用如下:

Boolean value = new Boolean(false);
change(value);
public static void change(Boolean bValue) {
        bValue = new Boolean(true);
    }

在调用这个方法的时候,会把你传的参数(value)指向的引用地址复制一份赋给方法参数(bValue),也就是这时调用方法时传递的参数(value)和定义方法时的参数(bValue)指向了同一个对象的引用地址,当执行bValue = new Boolean(true);时,会把新创建的对象也就是new Boolean(true)的地址赋给bValue,此时bValue已经不再指向value指向的对象了,而方法执行完毕,bValue作为方法的局部变量,会被销毁(这个change方法实际上是没有任何意义的)。所以value还是指向new Boolean(false)这个对象,所以打印出来还是false。
------解决方案--------------------
引用:
Quote: 引用:

你要去了解一下,值传递和地址传递 ,了解这个。你就明白为什么会这样

用了这么久一直以为都是引用传递啊,譬如说
public class Person{
  public int i = 0;
  public int j = 1;
}

void test(Person person) {
   person.i = 22;
   person.j = 33;
}

public static void main(String args[]) {
   Person p = new Person();
   test(p);
   System.out.println(p.i);
   System.out.println(p.j);
}


输出结果应该是:
22
33

这个作何解呢?

void set(int value) {
    value = 4;
}

这个的话肯定不会改变实参的值,但是对于上面那种对象类型的参数则会改变。
到底如何界定哪些情况下是值传递还是引用传递呢?



楼主 Java中传递的都是值,不过有些是内容值,有些是地址值 你可以这样来考虑你的这个问题:
p里存的是个指向person的地址,调用方法test,复制一份地址,两份地址都指向person对象,所以test方法中改变了person对象,那么原来的p那里的地址指向的person对象也就改变了。

至于你一楼的问题,也是同样的道理:
bValue里存放指向一个"false"的对象的地址,然后调用方法change,复制一份和bValue一样的地址给形参bValue(注意这两个bValue不一样,一个形参一个实参),然后形参指向了一个“true”的对象,但是和外面的实参没有任何关系。

以上是个人的想法,到底Java的发明者怎么考虑的,权威书籍是怎么写的,我不知道,我只是觉得这样考虑好像能够说明运行的结果