问:当一个对象被当作参数传递到一个方法后,此方法可改变这个对象的属性,并可返回变化后的结果,那么这里到底是值传递还是引用传递? 
(下面内存图解:栈内存是先进后出的,画错了 )
  答:是值传递。Java 编程语言只有值传递参数。当一个对象实例作为一个参数被传递到方法中时,参数的值就是该对象的引用一个副本。指向同一个对象,对象的内容可以在被调用的方法中改变,但对象的引用(不是引用的副本)是永远不会改变的。
  Java参数,不管是原始类型还是引用类型,传递的都是副本(有另外一种说法是传值,但是说传副本更好理解吧,传值通常是相对传址而言)。
  如果参数类型是原始类型,那么传过来的就是这个参数的一个副本,也就是这个原始参数的值,这个跟之前所谈的传值是一样的。如果在函数中改变了副本的值不会改变原始的值.
  如果参数类型是引用类型,那么传过来的就是这个引用参数的副本,这个副本存放的是参数的地址。如果在函数中没有改变这个副本的地址,而是改变了地址中的 值,那么在函数内的改变会影响到传入的参数。如果在函数中改变了副本的地址,如new一个,那么副本就指向了一个新的地址,此时传入的参数还是指向原来的 地址,所以不会改变参数的值。
基本类型参数传递:不改变值
 
引用类型参数传递:改变值
       
 
 
 
无论是什么语言,要讨论参数传递方式,就得从内存模型说起,主要是我个人觉得从内存模型来说参数传递更为直观一些。闲言少叙,下面我们就通过内存模型的方式来讨论一下Java中的参数传递。
这里的内存模型涉及到两种类型的内存:栈内存(stack)和堆内存(heap)。基本类型作为参数传递时,传递的是这个值的拷贝。无论你怎么改变这个拷贝,原值是不会改变的。看下边的一段代码,然后结合内存模型来说明问题:
public class ParameterTransfer {
     public static void main(String[] args) {
        int num = 30;
        System.out.println("调用add方法前num=" + num);
        add(num);
        System.out.println("调用add方法后num=" + num);
     }
  
     public static void add(int param) {
          param = 100;
     }
}          
这段代码运行的结果如下:
1
2
调用add方法前num=30
调用add方法后num=30
程序运行的结果也说明这一点,无论你在add()方法中怎么改变参数param的值,原值num都不会改变。
  下边通过内存模型来分析一下。
  当执行了int num = 30;这句代码后,程序在栈内存中开辟了一块地址为AD8500的内存,里边放的值是30,内存模型如下图:
                    
  执行到add()方法时,程序在栈内存中又开辟了一块地址为AD8600的内存,将num的值30传递进来,此时这块内存里边放的值是30,执行param = 100;后,AD8600中的值变成了100。内存模型如下图:   
                 
  地址AD8600中用于存放param的值,和存放num的内存没有任何关系,无论你怎么改变param的值,实际改变的是地址为AD8600的内存中的值,而AD8500中的值并未改变,所以num的值也就没有改变。
   以上是基本类型参数的传递方式,下来我们讨论一下对象作为参数传递的方式。
  先看下边的示例代码:
public class ParameterTransfer {
     public static void main(String[] args) {
          String[] array = new String[] {"huixin"};
          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] = "hello, world!";
     }
}   
运行的结果如下:
1
2
调用reset方法前array中的第0个元素的值是:huixin
调用reset方法后array中的第0个元素的值是:hello, world!
当对象作为参数传递时,传递的是对象的引用,也就是对象的地址。下边用内存模型图来说明。
       
  当程序执行了String[] array = new String[] {"huixin"}后,程序在栈内存中开辟了一块地址编号为AD9500内存空间,用于存放array[0]的引用地址,里边放的值是堆内存中的一个地址,示例中的值为BE2500,可以理解为有一个指针指向了堆内存中的编号为BE2500的地址。堆内存中编号为BE2500的这个地址中存放的才是array[0]的值:huixin。
  当程序进入reset方法后,将array的值,也就是对象的引用BE2500传了进来。这时,程序在栈内存中又开辟了一块编号为AD9600的内存空间,里边放的值是传递过来的值,即AD9600。可以理解为栈内存中的编号为AD9600的内存中有一个指针,也指向了堆内存中编号为BE2500的内存地址,如图所示:
       
  这样一来,栈内存AD9500和AD9600(即array[0]和param的值)都指向了编号为BE2500的堆内存。
  在reset方法中将param的值修改为hello, world!后,内存模型如下图所示:
       
  改变对象param的值实际上是改变param这个栈内存所指向的堆内存中的值。param这个对象在栈内存中的地址是AD9600,里边存放的值是BE2500,所以堆内存BE2500中的值就变成了hello,world!。程序放回main方法之后,堆内存BE2500中的值仍然为hello,world!,main方法中array[0]的值时,从栈内存中找到array[0]的值是BE2500,然后去堆内存中找编号为BE2500的内存,里边的值是hello,world!。所以main方法中打印出来的值就变成了hello,world!
  
小结:
  无论是基本类型作为参数传递,还是对象作为参数传递,实际上传递的都是值,只是值的的形式不用而已。第一个示例中用基本类型作为参数传递时,将栈内存中的值30传递到了add方法中。第二个示例中用对象作为参数传递时,将栈内存中的值BE2500传递到了reset方法中。当用对象作为参数传递时,真正的值是放在堆内存中的,传递的是栈内存中的值,而栈内存中存放的是堆内存的地址,所以传递的就是堆内存的地址。这就是它们的区别。
补充一下,在Java中,String是一个引用类型,但是在作为参数传递的时候表现出来的却是基本类型的特性,即在方法中改变了String类型的变量的值后,不会影响方法外的String变量的值。关于这个问题,可以参考如下两个地址:
http://freej.blog.51cto.com/235241/168676
http://dryr.blog.163.com/blog/static/58211013200802393317600/
我觉得是这两篇文章中提到的两个原因导致的,一个是String实际上操作的是char[],可以理解为String是char[]的包装类。二是给String变量重新赋值后,实际上没有改变这个变量的值,而是重新new了一个String对象,改变了新对象的值,所以原来的String变量的值并没有改变。

当一个对象被当作参数传递到一个方法后,此方法可改变这个对象的属性,并可返回变化后的结果,那么这里到底是值传递还是引用传递相关推荐

  1. java面试题:当一个对象被当作参数传递到一个方法后,此方法可改变这个对象的属性,并可返回变化后的结果,那么这里到底是值传递还是引用传递?

    java面试题:当一个对象被当作参数传递到一个方法后,此方法可改变这个对象的属性,并可返回变化后的结果,那么这里到底是值传递还是引用传递? 答:是值传递.Java编程语言只有值传递参数. 当一个对象实 ...

  2. Java中的值传递和引用传递

    当一个对象被当作参数传递到一个方法后,此方法可改变这个对象的属性,并可返回变化后的结果,那么这里到底是值传递还是引用传递?      答:是值传递.Java 编程语言只有值传递参数.当一个对象实例作为 ...

  3. Java值传递与引用传递

    Java面试题: 当一个对象被当作参数传递到一个方法后,此方法可改变这个对象的属性,并可返回变化后的结果,那么这里到底是值传递还是引用传递? 答案基本上是:值传递 说明:得出这种结论的前提必须是&qu ...

  4. 基础回顾(正则、循环、和、 int和Integer、String /StringBuffer、Array和ArrayList、值传递和引用传递、 Lamda、java8)

    1. 正则表达式 1.1 Java中是如何支持正则表达式操作的? Java中的String类提供了支持正则表达式操作的方法,包括:matches().replaceAll().replaceFirst ...

  5. java 地址传递 返回值_Java中的值传递和引用传递

    这几天一直再纠结这个问题,今天看了这篇文章有点思路了,这跟C++里函数参数为引用.指针还是有很大区别. 当一个对象被当作参数传递到一个方法后,此方法可改变这个对象的属性,并可返回变化后的结果,那么这里 ...

  6. string 引用没有设置为 string 的实例。 参数名: s_Java中的值传递和引用传递,看完这篇终于终于明白了!...

    当一个对象被当作参数传递到一个方法后,此方法可改变这个对象的属性,并可返回变化后的结果,那么这里到底是值传递还是引用传递?  答:是值传递.Java 编程语言只有值传递参数.当一个对象实例作为一个参数 ...

  7. java形参、实参、值传递、引用传递

    工作中,发现大多数人对值传递,引用传递理解不深,下面写一遍文章详细聊聊. 一.形参 形参:用来接收调用方法时传递的参数,只有在被调用时才分配内存,一旦调用结束,就释放内存空间.因此仅在方法内有效. p ...

  8. Java编程语言是什么传递,即值传递和引用传递的区别

    当一个对象被当作参数传递到一个方法后,此方法可改变这个对象的属性,并可返回变化后的结果,那么这里到底是值传递还是引用传递? 答案是:值引用 因为Java编程语言只有值传递参数. 当一个对象实例作为一个 ...

  9. java形参_java形参、实参、值传递、引用传递

    工作中,发现大多数人对值传递,引用传递理解不深,下面写一遍文章详细聊聊. 一.形参 形参:用来接收调用方法时传递的参数,只有在被调用时才分配内存,一旦调用结束,就释放内存空间.因此仅在方法内有效. p ...

最新文章

  1. OC实用转换model的工具
  2. 【笔记】基于边缘检测和BP神经网络的大豆杂草识别研究
  3. VTK:Utilities之SparseArray
  4. 好消息:VS 2008 and .NET 3.5 Beta 2 发布了
  5. linux服务器每次重启卡住,运维如何解决Linux服务器重启后命令无法正常使用的问题...
  6. 程序员秒懂的30个段子:看到第几个你笑了?
  7. Kubernetes 学习总结(23)—— 2022 年 Kubernetes 的 5 个趋势
  8. 计算Linux内存,CUP,硬盘使用率的shell脚本
  9. ES之各种运算符,for、while、do while 、switch case循环
  10. 使用jQuery.form插件,实现完美的表单异步提交
  11. thinkphp学习简易教程(一) thinkphp创建项目
  12. 纸壳cms php,纸壳CMS 3.4 发布,电商功能增强
  13. 主流数据库以及适用场景思维导图
  14. 2022道路运输企业安全生产管理人员复训题库及答案
  15. 中国一共有多少神仙!今天让大家开开眼!
  16. 服务器硬盘常用的阵列方式有几种,三种常见磁盘阵列设置
  17. 偶然发现的写参考文献的利器(超快搜索+快捷摘要总结)、文末再讲一下EndNote的使用心得
  18. linux下安装drcom方法
  19. UEFI和传统引导的区别
  20. Oracle的网络三大配置文件(sqlnet.ora、tnsnames.ora、listener.ora)

热门文章

  1. 人物 | 张忠谋:老将二度离场
  2. 项目开发-树形层级结构中的数量统计
  3. 涨粉写作经验分享(一) - 写作技巧
  4. Flink SQL 自定义 redis connector
  5. Broadcast 的使用
  6. ALtera DE2开发板学习03
  7. linux恢复安卓数据,安卓数据恢复2 - ranfs的个人空间 - OSCHINA - 中文开源技术交流社区...
  8. 如果将网页素材转为html,html/css
  9. linux系统日志管理详解
  10. 快速学会开发微信小程序教程