黑马程序员——JAVA——参数传递机制

来源:互联网 发布:网络说唱歌曲大连站 编辑:程序博客网 时间:2024/06/05 23:53

------Java培训、Android培训、iOS培训、.Net培训、期待与您交流! -------

昨天在论坛上看到个人问了个这样的问题。

public class  Test{        public static void main(String[] args)         {                String string = "Hello";                test(string);                System.out.println(string);        }        public static void test(String str)        {                str = "World";        }}
为什么输出的是Hello而不是World?


说到这个问题就不得不提到java的参数传递机制。

一般来说参数传递的方式有两种:值传递和引用传递。

但是在JAVA中不存在引用传递,JAVA编程语言只有值传递。

JAVA中的参数传递,不论是值传递还是引用传递,其本质上传递的都是副本(其实就是值,我看有的帖子上称为副本,可能是值与值传递容易弄混,这里也称为副本)。


——当传递的参数类型是基本数据类型时,那么传过来的就是这个参数的一个副本,也就是原始参数的值。如果在函数中,副本中的值进行了变动,原始参数的值并不会随着副本的值而改动。

——当传递的参数类型是引用数据类型时,那么传过来的也是这个参数的一个副本,只不过这个副本是原始参数的地址的值。如果在函数中,副本中的地址没有进行变动,而是改变了地址中的某个值,那么函数内的变动会影响原始参数。如果在函数中,副本中的地址发生了改变,比如new了个新的对象,那么副本就指向了这个新的对象,而原始参数不会因为函数内的变动而变动。


下面分别从两种传递方式的内存模型讨论下java中的参数传递。

基本数据类型:

public class Demo1{public static void main(String[] args) {    int num = 3;    System.out.println("调用add方法前num=" + num);    test(num);    System.out.println("调用add方法后num=" + num);}public static void test(int num) {num = 5;}} 
运行结果: 调用add方法前num=3
调用add方法后num=3

内存:当执行int num = 3;程序在栈内存中开辟了一个新内存(如地址为0x13001),并存放了3这个数值。当执行到test方法时,程序又开辟了一个新的内存(如地址为0x13002),并将num的值3传了进来,此时num的值是3。当执行到num=5;后,0x13002地址中的值变成了5。

也就是说地址0x13002是函数中副本的地址,无论副本怎么改变,原始参数都不会发生变化。

引用数据类型:

public class Demo1{public static void main(String[] args) {        String[] array = new String[] {"Hello"};        System.out.println("调用reset方法前array中的第0个元素的值是:" + array[0]);        reset(array);        System.out.println("调用reset方法后array中的第0个元素的值是:" + array[0]);   }   public static void reset(String[] param) {        param[0] = "World";   }}  
运行结果: 调用reset方法前array中的第0个元素的值是:Hello
调用reset方法后array中的第0个元素的值是:World

内存:当程序执行到String[] array = new String[] {"Hello"};时,程序在堆内存中new了一个新的对象地址为0x13001,并把这个地址给了栈内存中开辟了一个空间的array。当春训运行到reset方法时,程序如基本数据类型那样同样在内存中开辟了一个新空间存放param,并把array中存放的地址0x13001给了param,也就是说此时param也指向了0x13001这个地址。之后执行赋值语句param[0] = "World";,是对0x13001这二个地址中的值进行修改。所以原始参数中0x13001的值也进行了变动。

也就是说地址0x13001是作为一个值被传递进函数的,只要这个值没有改变(如不new新对象),通过这个地址对参数进行修改,原始参数的值也会改变的。


总结:无论是基本数据类型还是引用数据类型,进行的都是值传递,只不过值的形式不同一个传的是值,一个传的是地址。


最后再来看看一开始的问题。

test方法中传递的是一个字符串的地址,按理来说只要函数中不new新字符串,原始字符串中的值就会随着函数中的变动进行变化。

然而函数中的str = "World";相当于new了个新的字符串(str=new String("World");)。所以函数中的改动并没有影响原始参数。


0 0
原创粉丝点击