【解惑】Java方法参数是引用调用还是值调用?

最近找实习,在笔试时候做了下面这道题:求下面代码的输出结果。

public class MyClass {

static void aMethod(StringBuffer sf1,StringBuffer sf2){
sf1.append(sf2);
sf2=sf1;
}

public static void main(String[] args){
StringBuffer sf1=new StringBuffer("A");
StringBuffer sf2=new StringBuffer("B");
aMethod(sf1,sf2);
System.out.println(sf1+":"+sf2);
}
}

我当时想到的输出结果是:   AB:AB。   很显然掉进出题人的圈套里边了,正确答案应该是AB:B。

由于长时间没看JAVA,可能有些知识点生疏了,这道题就考了JAVA的值调用。

java程序设计语言中,方法参数的使用情况要注意三点:

●一个方法不能修改一个基本数据类型的参数(即数值型和布尔型)

●一个方法可以改变一个对象参数的状态

●一个方法不能实现让对象参数引用一个新的对象。

为了更好地理解,我看了一位博友的博客,内容如下:

转载于:http://hxraid.iteye.com/blog/428856

方法调用(call by) 是一个标准的计算机科学术语。方法调用根据参数传递的情况又分为值调用( call by reference ) 引用调用( call by value ) 。江湖上有很多关于这两种调用的定义 ,最通常的说法是传递值的是值调用,传递地址的是引用调用。这其实很不恰当,这种 这些说法很容易让我们联想到Java的对象参数传递是引用调用,实际上,Java的对象参数传递仍然是值调用 。

我们首先用一段代码来证实一下为什么Java的对象参数传递 是值调用。

Java代码  

  1. public class Employee {
  2. public String name=null;
  3. public Employee(String n){
  4. this.name=n;
  5. }
  6. //将两个Employee对象交换
  7. public static void swap(Employee e1,Employee e2){
  8. Employee temp=e1;
  9. e1=e2;
  10. e2=temp;
  11. System.out.println(e1.name+" "+e2.name); //打印结果:李四 张三
  12. }
  13. //主函数
  14. public static void main(String[] args) {
  15. Employee worker=new Employee("张三");
  16. Employee manager=new Employee("李四");
  17. swap(worker,manager);
  18. System.out.println(worker.name+" "+manager.name); //打印结果仍然是: 张三 李四
  19. }
  20. }

上面的结果让人很失望,虽然形参对象e1,e2的内容交换了,但实参对象worker,manager并没有互换内容。这里面最重要的原因就在于形参e1,e2是实参worker,manager的地址拷贝。

大家都知道,在Java中对象变量名实际上代表的是对象在堆中的地址(专业术语叫做对象引用 )。在Java方法调用的时候,参数传递的是对象的引用。重要的是,形参和实参所占的内存地址并不一样,形参中的内容只是实参中存储的对象引用的一份拷贝。

如果大家对JVM内存管理中Java栈 局部变量区 有所了解的话(可以参见《 Java 虚拟机体系结构 》),就很好理解上面这句话。在JVM运行上面的程序时,运行main方法和swap方法,会在Java栈中先后push两个叫做栈帧的内存空间。main栈帧中有一块叫局部变量区的内存用来存储实参对象worker和manager的引用。而swap栈帧中的局部变量区则存储了形参对象e1和e2的引用。虽然e1和e2的引用值分别与worker和manager相同,但是它们占用了不同的内存空间。当e1和e2的引用发生交换时,下面的图很清晰的看出完全不会影响worker和manager的引用值。

Java对象参数传递虽然传递的是地址(引用),但仍然是值调用。是时候需要给引用调用和值调用一个准确的定义了。

 值调用(call by value) : 在参数传递过程中,形参和实参占用了两个完全不同的内存空间。形参所存储的内容是实参存储内容的一份拷贝。实际上,Java对象的传递就符合这个定义,只不过形参和实参所储存的内容并不是常规意义上的变量值,而是变量的地址。咳,回过头想想:变量的地址不也是一种值吗!

引用调用(call by reference) : 在参数传递的过程中,形参和实参完全是同一块内存空间,两者不分彼此。实际上,形参名和实参名只是编程中的不同符号,在程序运行过程中,内存中存储的空间才是最重要的。不同的变量名并不能说明占用的内存存储空间不同。

大体上说,两种调用的根本并不在于传递的是值还是地址(毕竟地址也是一个值),而是在于形参和实参是否占用同一块内存空间。事实上,C/C++的指针参数传递也是值调用,不信试试下面的C代码吧!

C代码  

  1. #include<stdio.h>
  2. void swap(int *a1,int *b1){
  3. int *t=a1;
  4. a1=b1;
  5. b1=t;
  6. }
  7. int main(){
  8. int x1=100;
  9. int x2=200;
  10. int *a=&x1;
  11. int *b=&x2;
  12. printf("%d %d\n",*a,*b);
  13. swap(a,b);
  14. printf("%d %d\n",*a,*b);
  15. return 0;
  16. }

但C/C++是有引用调用的,这就是C/C++一种叫做引用的变量声明方法: int a; int &ra=a; 其中ra是a的别名,两者在内存中没有区别,占用了同一个内存空间。而通过引用(别名)的参数传递就符合引用调用的特点了。大家可以去试试

void swap(int &a1,int &b1);的运行结果。

时间: 2025-01-01 21:04:01

【解惑】Java方法参数是引用调用还是值调用?的相关文章

java方法参数传递面试题

传值还是传引用是Java中很基础的一个问题,也是笔试的时候经常被考察的一个问题,总结一下. 题目1: 写出以下程序的输出内容. public class Test { public static void changeValue(int value){ value = 0; } public static void main(String[] args) { int value = 2010; changeValue(value); System.out.println(value); } }

java方法参数传递方式只有----值传递!

在通常的说法中,方法参数的传递分为两种,值传递和引用传递,值传递是指将实际参数复制一份传递到方法中, 在方法中的改动将不会影响到实际参数本身,而引用传递则是指传递的是实际参数本身,在方法中的改动将会影响到实 际参数本身.但是,在java中只有值传递,没有引用传递!那么,为什么当方法参数是基本数据类型时表现是值传递, 而当是引用类型时表现的是引用传递形式呢? Java内存区域中含有java堆和虚拟机栈两个内存区域(并不是只是将java内存区分为这两个内存区域,此外还有程 序计数器,本地方法栈以及方

java 方法参数-值调用,引用调用问题

(博客内容来自于core java卷一) 1. xx调用:程序设计语言中方法参数的传递方式: 引用调用(call by reference):表示方法接收的是调用者提供的变量地址. 值调用(call by value):表示方法接收的是调用者提供的值. 命名调用(call by name):已经成为历史. 2. Java使用值调用,而且只有值调用.也就是说方法得到的是参数值的一个拷贝,并不是参数值本身,所以,方法不能修改传递给它的的任何参数变量本身. 看下面代码: public class te

辨析Java方法参数中的值传递和引用传递

小方法大门道 小瓜瓜作为一个Java初学者,今天跟我说她想通过一个Java方法,将外部变量通过参数传递到方法中去,进行逻辑处理,方法执行完毕之后,再对修改过的变量进行判断处理,代码如下所示. public class MethodParamsPassValue { public static void doErrorHandle() { boolean a = false; int b = 5; passBaseValue(a, b); if (a == true || b == 10) { S

Java 方法重载与引用数组类型

1.方法重载 1)方法的签名 方法的签名包含方法名和参数列表 一个类中,不可以有两个方法的签名完全相同,即一个类中不能有两个方法的方法名和参数列表都一样. public class Test{ public void print(int x){...}; public void print(int x){...}; //编译错误,方法签名不能一样 } public class Test{ public void print(int x){...}; public boolean print(in

Java方法参数的传递方式

程序设计语言中,将参数传递给方法(或函数)有两种方法.按值传递(call by value)表示方法接受的是调用者提供的值:按引用调用(call by reference)表示方法接受的是调用者提供的变量地址.Java程序设计语言都是采用按值传递.下面通过例题进行说明: 1 public class ParamTest { 2 public static void main(String[] args) { 3 /* 4 *Test1: Methods can't modify numeric

java方法参数

java程序设计语言总是采用按值调用.也就是说,方法得到的是所有参数值的一个拷贝,特别:方法不能修改传递给它的任何参数变量的内容. 方法参数共有两种类型: 1.基本类型(数字,布尔值). 2.对象引用. java中方法参数的使用情况: 1.一个方法不能修改一个基本数据类型的参数(数值 布尔型). 2.一个方法可以改变一个对象参数的状态. 3.一个方法不能让对象参数引用一个新的对象. 一个方法不可能修改一个基本数据类型的参数,而对象引用作为参数就不同了

Java中参数的引用传递和值传递

1.一些定义 值传递:把实际传入参数的值,在内存中赋值一份 引用传递:传入的是实际参数的地址 2.传递基本类型的参数 因为Java是值传递,那就不难理解下面的代码不交换任何值 swap(Type arg1, Type arg2) { Type temp = arg1; arg1 = arg2; arg2 = temp; } 3.传递引用变量的参数 Java都是通过引用来操作对象的,所有指向对象的变量都是引用,然而,Java不会把引用传递给方法的参数,而是引用的值: 那么,为什么对象的成员值可以改

Java的方法参数-想想挺有趣的问题

一直认为Java的方法参数都是传递值,调用后对本身不影响. Java不存在C/C++中的指针,在快速排序中,传入的数组,却发生了值的改变.由此引发的思考: //为方便举例,以下为部分快速排序伪代码 传入的数组,在递归中,数组值被操作. void quickSort(int s[], int l, int r){ if (l < r){ quickSort(s, l, i - 1); quickSort(s, i + 1, r); } } 结论:Java方法参数中传递的是值,在参数是引用类型(如数