[1]Java中的值传递和引用传递
2017年12月23日更新:Java中就是”传值”的,所谓的”传引用”,是指对于引用类型的对象,使用new+构造函数的方式创建实例后,会返回一个引用值,通过这个值能找到这个对象中的所有成员。然后把这个值赋给了这个类型的变量,本质上还是传值的!
而引用对象之间的赋值运算,显然赋的就是这个引用值,所以说Java赋值的本质就是传值。
以下是原来的理解:
网上比较盛行的说法是,Java中是完全采用值传递的,一些时候看到的”引用传递”的表象实际上传递的是引用的值,也就是创建了引用的副本。
实际上这是一个比较复杂的问题,众说纷纭,现在只了解一下几个常见的参数传递的结果,而暂时不去深究到底什么样叫真正意义上的”引用传递”了。
可以看到基本数据类型传递参数直接将自己的值拷贝给形参了,而引用类型拷贝了一份句柄或指针(这两种用哪个要取决于JVM)。
package day31;
class Person{
int age=0;
String name="none";
@Override
public String toString() {
return "age="+age+",name="+name;
}
}
public class Test {
public static void main(String[] args) {
int a=1;
fun1(a);
String str="Hello world";
fun2(str);
char c='k';
fun3(c);
Person p=new Person();
fun4(p);
System.out.println(a+"\n"+str+"\n"+c+"\n"+p);
}
private static void fun4(Person p) {
p.age=20;
p.name="lzh";
}
private static void fun3(char c) {
c='j';
}
private static void fun2(String str) {
str="changed";
}
private static void fun1(int a) {
a+=1;
}
}
运行结果:
1
Hello world
k
age=20,name=lzh
对于上面的基本类型,都是创建了局部自动变量,拷贝了实参的值,然后修改了局部自动变量的值,也就不改变原来的值,这和C++非常类似。
对于引用类型,如String str,则是先拷贝出了一个新的引用(仍关联实参的句柄或指针):
然后这里对新的局部的str用了赋值运算符”=”,这个符号在这里应理解为”舍弃原有的对象,而去链接一个其它的对象”,执行完后是这样的:
实际上,String是final的所以给了值以后不能再修改,如果是一个拥有修改内部属性的方法的引用类型,就可以通过这样的方法来修改内部属性从而改变实参:
要想引用类型形参不影响实参,可以让这个拷贝来的引用去链接新的对象:
package day31;
class Person{
int age=0;
String name="none";
@Override
public String toString() {
return "age="+age+",name="+name;
}
}
public class Test {
public static void main(String[] args) {
Person p=new Person();
fun5(p);
System.out.println(p);
}
private static void fun5(Person p) {
p=new Person();
p.age=20;
p.name="lzh";
}
}
运行结果:
age=0,name=none
[2]Eclipse单步调试
保存后,更改为调试视图:
双击打断点,至少打一个断点作为调试起始点:
开始调试:
会先运行到第一个断点处,灰绿框表示下一步即将执行的那句:
F5单步跳入,表示一句一句执行,遇到函数会跳入:
F6单步跳过,表示一句一句执行,遇到函数会跳过:
当跳入了不想关注细节的函数内时,按F7会跳出这个函数:
F8会直接运行到下一个断点处去:
在右上角窗口可以看到各个变量的值。当某一步使某些变量的值变化时会作高亮显示。当发现某个错误使某个值错误时,为了暂时保证后续调试的正常进行,可以右键修改它的当前值:
[3]留下的疑问
单步执行过滤器如何使用?
在首选项里也能找到它的设置。