Java中只有值传递,没有引用传递

By | 08月04日
Advertisement

今天,我在一本面试书上看到了关于java的一个参数传递的问题:

写道

java中对象作为参数传递给一个方法,到底是值传递,还是引用传递?

我毫无疑问的回答:“引用传递!”,并且还觉得自己对java的这一特性很是熟悉!

结果发现,我错了!

答案是:

值传递!Java中只有按值传递,没有按引用传递!

回家后我就迫不及待地查询了这个问题,觉得自己对java这么基础的问题都搞错实在太丢人!

综合网上的描述,我大概了解了是怎么回事,现在整理如下,如有不对之处望大神提出!

先来看一个作为程序员都熟悉的值传递的例子:

Java代码 Java中只有值传递,没有引用传递

  1. ... ...
  2. //定义了一个改变参数值的函数
  3. public static void changeValue(int x) {
  4. x = x *2;
  5. }
  6. ... ...
  7. //调用该函数
  8. int num = 5;
  9. System.out.println(num);
  10. changeValue(num);
  11. System.out.println(num);
  12. ... ...

答案显而易见,调用函数changeValue()前后num的值都没有改变。

由此做一个引子,我用图表描绘一个值传递的过程:

Java中只有值传递,没有引用传递

num作为参数传递给changeValue()方法时,是将内存空间中num所指向的那个存储单元中存放的值,即"5", 传送给了changeValue()方法中的x变量,而这个x变量也在内存空间中分配了一个存储单元,这个时候,就把num的值5传送给了这个存储单元 中。此后,在changeValue()方法中对x的一切操作都是针对x所指向的这个存储单元,与num所指向的那个存储单元没有关系了!

自然,在函数调用之后,num所指向的存储单元的值还是没有发生变化,这就是所谓的“值传递”!值传递的精髓是:传递的是存储单元中的内容,而非地址或者引用!

接下来,就来看java中的对象参数是怎么传递的:

同样,先给出一段代码:

Java代码 Java中只有值传递,没有引用传递

  1. ... ...
  2. class person {
  3. public static String name = "Jack";
  4. ... ...
  5. }
  6. ... ...
  7. //定义一个改变对象属性的方法
  8. public static void changeName(Person p) {
  9. p.name = "Rose";
  10. }
  11. ... ...
  12. public static void main(String[] args) {
  13. //定义一个Person对象,person是这个对象的引用
  14. Person person = new Person();
  15. //先显示这个对象的name属性
  16. System.out.println(person.name);
  17. //调用changeName(Person p)方法
  18. changeName(person);
  19. //再显示这个对象的name属性,看是否发生了变化
  20. System.out.println(person.name);
  21. }

答案应该大家都心知肚明:

第一次显示:“Jack”

第二次显示:“Rose”

方法用了一个对象参数,该对象内部的内容就可以改变,我之前一直认为应该是该对象复制了一个引用副本给调用函数的参数,使得该方法可以对这个对象进行操作,其实是错了!

http://www.cnblogs.com/clara/archive/2011/09/17/2179493.html 写道

Java 编程语言只有值传递参数。当一个对象实例作为一个参数被传递到方法中时,参数的值就是该对象的引用一个副本。指向同一个对象,对象的内容可以在被调用的方法中改变,但对象的引用(不是引用的副本)是永远不会改变的。

为什么这里是“值传递”,而不是“引用传递”?

我还是用图表描绘比较能解释清楚:

Java中只有值传递,没有引用传递

主函数中new 了一个对象Person,实际分配了两个对象:新创建的Person类的实体对象,和指向该对象的引用变量person。

【注意:在java中,新创建的实体对象在堆内存中开辟空间,而引用变量在栈内存中开辟空间】

正如如上图所示,左侧是堆空间,用来分配内存给新创建的实体对象,红色框是新建的 Person类的实体对象,000012是该实体对象的起始地址;而右侧是栈空间,用来给引用变量和一些临时变量分配内存,新实体对象的引用person 就在其中,可以看到它的存储单元的内容是000012,记录的正是新建Person类实体对象的起始地址,也就是说它指向该实体对象。

这时候,好戏上台了:

调用了changeName()方法,person作为对象参数传入该方法,但是大 家特别注意,它传入的是什么!!!person引用变量将自己的存储单元的内容传给了changeName()方法的p变量!也就是将实体对象的地址传给 了p变量,从此,在changeName()方法中对p的一切操作都是针对p所指向的这个存储单元,与person引用变量所指向的那个存储单元再没有关 系了!

回顾一下上面的一个值传递的例子,值传递,就是将存储单元中的内容传给调用函数中的那个参数,这里是不是异曲同工,是所谓“值传递”,而非“引用传递”!!!

那为什么对象内部能够发生变化呢?

那是因为:p所指向的那个存储单元中的内容是实体对象的地址,使得p也指向了该实体对象,所以才能改变对象内部的属性!

这也是我们大多数人会误以为是“引用传递”的终极原因!!!

附:

堆内存用来存放由new创建的对象和数组。 在堆中分配的内存,由Java虚拟机的自动垃圾回收器来管理。
在堆中产生了一个数组或对象后,还可以 在栈中定义一个特殊的变量,让栈中这个变量的取值等于数组或对象在堆内存中的首地址,栈中的这个变量就成了数组或对象的引用变量。 引用变量就相当于是 为数组或对象起的一个名称,以后就可以在程序中使用栈中的引用变量来访问堆中的数组或对象。引用变量就相当于是为数组或者对象起的一个名称。

参考:

http://guhanjie.iteye.com/blog/1683637

Similar Posts:

  • JAVA中的值传递与引用传递

    原帖地址:http://zlahst.iteye.com/blog/48292 关于对值传递与引用传递我一直似是而非. 今天有个朋友问起我这个问题的时候我还是很困惑. 对值传递我还是用一个例子来说明一下吧: public class Test { public static void test(boolean test) { test = ! test; System.out.println("In test(boolean) : test = " + test); } public

  • Java语言中的值传递与引用传递

    JAVA语言中的传递都是值传递吗?有没有引用传递呢?这是一个常常被讨论的问题.开始以前首先来看下面的代码: public class TestParameter { // 初始值为0 protected int num = 0; // 为方法参数重新赋值 public void change(int i) { i = 5; } // 为方法参数重新赋值 public void change(TestParameter t) { TestParameter tmp = new TestParame

  • Java中的值传递和引用传递实例介绍

    代码如下: package Object.reference; public class People { private String name; private int age; public People(){ } public People(String name, int age) { super(); this.name = name; this.age = age; } public String toString(){ return "name:" + name + &

  • java中的值传递和引用传递区别

    值传递:(形式参数类型是基本数据类型):方法调用时,实际参数把它的值传递给对应的形式参数,形式参数只是用实际参数的值初始化自己的存储单元内容,是两个不同的存储单元,所以方法执行中形式参数值的改变不影响实际参数的值. 引用传递:(形式参数类型是引用数据类型参数):也称为传地址.方法调用时,实际参数是对象(或数组),这时实际参数与形式参数指向同一个地址,在方法执行中,对形式参数的操作实际上就是对实际参数的操作,这个结果在方法结束后被保留了下来,所以方法执行中形式参数的改变将会影响实际参数. 测试总结

  • JAVA中值传递和引用传递,抽象类,接口的概念

    一.Java中的值传递和引用传递 值传递:方法调用时,实际参数把它的值传递给形式参数,方法执行过程中形参的改变和实参的改变会不影响. 这种传递是对于基础数据类型来说的. 引用传递:也称为传地址.方法调用的时候,实际参数的引用(地址,而不是参数的值)被传递给方法中相应的形式参数,在方法执行中,对形式参数的操作实际上就是对于实际参数的操作,方法执行过程中形式参数的改变将会影响实际参数的值. 二.1:抽象方法: 当父类的某个方法都会被子类重写时,那么父类的方法就没有 实现的必要.但必须要声明. 所以这

  • YY之Java中的值传递和引用传递

    貌似关于Java中方法调用时参数的传递是值传递还是引用传递的讨论从来就没有停止过,大致有两种流派:1,基本类型是按值传递,引用类型为引用传递.2,Java中只有值传递. 两方都引用了很多论据证明自己的说法是正确,但是到现在也没有一个公认的结论... 对于这个问题我是这么理解的:两种说法都对,只不过是叫法和看问题的角度不同. 我个人认为当实参为引用类型的时候,当发生方法调用,实参传递给形参的,是实参中存储的内存地址的一个拷贝,这个拷贝出来的副本的"值"和原实参中存储的内存地址的"

  • Java的对象是采用值传递还是引用传递?

    关于Java中的值传递我一开始是有点搞混的 值传递表示传递的是调用者的值 引用调用表示传递的是调用者提供的变量地址 所以重新再梳理一下 package Test; public class Test { public static void main(String[] args){ Test test = new Test(); Student stu_a = test.new Student("Bob"); Student stu_b = test.new Student("

  • 【java】值传递和引用传递理解

    一.理解 ★ 当一个变量最为一个参数传入方法内部的时候,会有两种不同的传递方式:值传递和引用传递. ☆ 值传递的特点:不管方法内部对传进去的参数作任何改变,也不会影响方法外部的变量的值 ☆ 引用传递的特点:方法内部对传进去的参数作的改变也会影响方法外部的变量的值 二.记忆 ★ 1.基本类型(8种)的传递都是值传递 ★ 2.引用类型(除String外)都是引用传递(传递引用的副本) ★ 3.Strng比较特殊,它虽然是引用类型,但是却是值传递 三 示例 3.1 基本类型:如 int Java代码

  • 值传递和引用传递----java

    本文章来自于http://hi.baidu.com/xzhilie/blog/item/8bc05c8dbdc86816b21bbae3.html 首先,推荐对Java有一定理解的同仁一本书<Practical Java>.在<Practical Java>中也有一个章节介绍Java中关于传值和传引用的问题,堪称经典.<Practical Java>在Java中,事实上底层工作原理不存在传引用的概念,这也象<Practical Java>中所说的那样,Jav

  • 10045---Java中的值传递和引用传递

    原文 当一个对象被当作参数传递到一个方法后,此方法可改变这个对象的属性,并可返回变化后的结果,那么这里到底是值传递还是引用传递?      答:是值传递.Java 编程语言只有值传递参数.当一个对象实例作为一个参数被传递到方法中时,参数的值就是该对象的引用一个副本.指向同一个对象,对象的内容可以在被调用的方法中改变,但对象的引用(不是引用的副本)是永远不会改变的. Java参数,不管是原始类型还是引用类型,传递的都是副本(有另外一种说法是传值,但是说传副本更好理解吧,传值通常是相对传址而言).

Tags: