- 论坛徽章:
- 0
|
看来不少同志对这里还有误会,具体说一下吧
java语言里面参数传递全部都是传值的,也就是把实参复制一份出来赋值给形参
大家都知道java数据类型有两类,值类型和引用类型,应该也知道值类型和引用类型都存在什么位置吧?
一般来说简单数据类型变量存放在栈里面,引用类型的变量。。。也是存放在栈里面的,我是说引用!至于对象是放在堆里面的。
例如有一个A类
- public class A{
- int i = 10;
- }
复制代码
先来创建个对象
- .....
- A a = new A();
- .....
复制代码
new A()的时候堆中产生了一个A类对象,并且有个int型的属性i,其值是10
并且赋值给了一个A类的引用a,也就是引用a指向一个A类对象
再来看个赋值
把引用a赋值给了引用a1,现在的状况是栈里面有两个A类引用a和a1,他们在栈内的值是相同的,按照C指针的观点来说,a和a1存放的是同一个地址,按照java的说法,a和a1引用到了同一个对象。那么对于a或者a1的操作其实都是操作着同一个对象。例如
- ....
- a.i = 20;
- System.out.println(a1.i); //echo 20
- ....
复制代码
那么,现在再来说参数传递的问题,弄个Test类
- public class Test{
- public static void func(A b){
- b.i = 20;
- }
- public static void main(String[] args){
- A a = new A();
- System.out.println(a.i); // echo 10;
- func(a); //把a.i属性变成20
- System.out.println(a.i); //echo 20;
- }
- }
复制代码
这不是传的引用,或者说传指针嘛?
不!这是一个美丽的误会,事实上是这样的
当调用func(a)方法的时候,a是一个A类对象的引用,它存在于栈中,是把a这个引用的值,也就是栈里面这个值赋值了一份赋值给了形参b,相当于b=a的操作。
所以实际上func方法里面的形参变量b和main方法中的局部变量a是两个栈里面的变量,但是他们引用到了同一个A类对象,所以修改任何一个,另外一个会跟着变动
若说传引用或者传指针也是达到一样的效果。是的,但若传的是指针的话,应该对形式参数赋值也会影响到实际参数(请回忆下C里传地址的有关知识),可事实并非这样,在方法内给形参赋值只改变了方形参的值并不会改变实参的值,原因也就是形参跟实参实际上是两个引用,只不过当把实参的值传递过来的时候两个引用的值相等了,也就是引用到了同一个对象。而传指针,应该是形参指向实参,那b里面存放的就成了a这个引用的地址了。
所以,java的参数传递全部都是传值的,而不是传址的。
传值是把实参的值取出来赋值给形参,传址是把实参的地址取出来赋值给形参。
取出来的值是栈里面的值,对于简单变量那就是变量值,而对于引用类型而言,那就是这个对象的引用。引用的值应该基本可以看做是对象的地址了。
其实perryhg版主的帖子写的很明白了。。。。
另外,对于String的问题,顺便说一句,String类是个不可变类,它的对象一旦创建就不会在改变。
说String特殊,并不是为了char*这样的用法作为基本数据类型的补充,而是在于它创建对象的赋值方式。一般类对象需要用new操作符创建,而String除了new之外,可以直接赋值,也就是说java承认你在源代码中写一对双引号就是一个String类型的对象了。也就是说
- String s = "abc"; //这里有个字符串对象“abc”,s是它的引用
- s = "bcd"; //这里给s引用赋了个新对象“bcd”,现在实际上有两个String对象"abc"和"bcd",不是说abc这个对象改变成了"bcd"的样子
复制代码
那么楼主里面
- public static void change(String str)
- {
- str ="new";
- }
复制代码
实际上就是给str这个形参赋了个新的字符串对象。这跟我在15楼给的例子其实一个样子的
- public static void func(A a){
- a = new A();
- a.i = 15;
- }
复制代码
根本就是给形参赋了新值,而java参数传递是传值的。所以不会把实参改了,最后怎么调用change也只会打印出来传递之前的实参的值,因为传进去之后,形参和实参指向了两个对象了,改形参对象,对实参引用到的对象没作用
upstorm,呵呵,你是不会用错,不过概念上有错误 |
|