文档章节

java方法参数和C方法参数的区别

墙头草
 墙头草
发布于 2011/09/09 11:17
字数 1050
阅读 92
收藏 0
方法调用(call by) 是一个标准的计算机科学术语。方法调用根据参数传递的情况又分为值调用( call by reference ) 和引用调用( call by value ) 。江湖上有很多关于这两种调用的定义 ,最通常的说法是传递值的是值调用,传递地址的是引用调用。这其实很不恰当,这种 这些说法很容易让我们联想到Java的对象参数传递是引用调用,实际上,Java的对象参数传递仍然是值调用 。

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

public class Employee {  
 
    public String name=null;  
      
    public Employee(String n){  
        this.name=n;  
    }  
    //将两个Employee对象交换  
    public static void swap(Employee e1,Employee e2){  
        Employee temp=e1;  
        e1=e2;  
        e2=temp;  
                System.out.println(e1.name+" "+e2.name); //打印结果:李四 张三  
    }  
    //主函数  
    public static void main(String[] args) {  
        Employee worker=new Employee("张三");  
        Employee manager=new Employee("李四");  
        swap(worker,manager);  
        System.out.println(worker.name+" "+manager.name); //打印结果仍然是: 张三 李四  
    }  

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

      大家都知道,在Java中对象变量名实际上代表的是对象在堆中的地址(专业术语叫做对象引用 )。在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代码吧!

#include<stdio.h>  
void swap(int *a1,int *b1){   EMS指南
    int *t=a1;  
    a1=b1;  
    b1=t;  
}  
int main(){  
    int x1=100;  
    int x2=200;  
        int *a=&x1;  
    int *b=&x2;  
    printf("%d %d\n",*a,*b);  
    swap(a,b);  
    printf("%d %d\n",*a,*b);  
    return 0;  

© 著作权归作者所有

墙头草
粉丝 16
博文 145
码字总数 117172
作品 0
卢湾
私信 提问
java基础重点讲解,看了还不会找我(四)

###04.01Java语言基础(循环结构概述和for语句的格式及其使用) A:循环结构的分类 for,while,do...while B:循环结构for语句的格式: for(初始化表达式;条件表达式;循环后的操作表达式) { 循环体...

谢小芳是女神
2018/12/30
0
0
JNI的提高,Java类型和C(C++)类型转换源代码

JNI的环境准备就不说了, 网上大把大把的, 这里讲到的内容层次稍微深一点, 涉及Java和C的类型问题, 并配了实际案例的源代码。 JNI大体的流程是: Java端发起调用, 使C端的代码运行, 此时从Jav...

晨曦之光
2012/03/09
2.1K
0
jdk8新特性之双冒号 :: 用法及详解

jdk8的新特性有很多,最亮眼的当属函数式编程的语法糖,本文主要讲解下双冒号::的用法。 概念 类名::方法名,相当于对这个方法闭包的引用,类似js中的一个function。比如: (Function在jav...

wangbo888
2018/09/04
2.2K
3
Java8 - lambda 表达式

lambda表达式 为什么需要lambda 表达式 函数对 Java 而言并不重要,在 Java 的世界里,函数无法独立存在。Lambda 表达式为 Java 添加了缺失的函数式编程特点,使我们能将函数当做一等公民看待...

秋风醉了
2018/08/29
130
0
用 JNI 进行 Java 编程(3)

从 C/C++ 程序调用 Java 代码 概述 JNI 允许您从本机代码内调用 Java 类方法。要做到这一点,通常必须使用 Invocation API 在本机代码内创建和初始化一个 JVM。下列是您可能决定从 C/C++ 代码...

Jerikc
2012/10/08
165
0

没有更多内容

加载失败,请刷新页面

加载更多

VMware vSphere ESXi主机的访问控制

在vShpere中,访问ESXi主机的途径很多,如下: ESXi DCUI ESXi Shell ESXi SSH ESXi Host Client vCenter --> vSphere web client / vSphere Client VMware vSphere ESXi主机的访问控制,除了......

大别阿郎
40分钟前
4
0
大神讲解CGI、FastCGI和PHP-FPM关系图解

参考资料 概念了解:CGI,FastCGI,PHP-CGI与PHP-FPM:http://www.nowamagic.net/librarys/veda/detail/1319 php中fastcgi和php-fpm是什么东西:https://www.zybuluo.com/phper/note/50231 ......

网络小虾米
49分钟前
5
0
《DNS攻击防范科普系列3》 -如何保障 DNS 操作安全

引言 前两讲我们介绍了 DNS 相关的攻击类型,以及针对 DDoS 攻击的防范措施。这些都是更底层的知识,有同学就来问能否讲讲和我们的日常操作相关的知识点,今天我们就来说说和我们日常 DNS 操...

Mr_zebra
50分钟前
4
0
zk中ServerCnxn

实现接口Stats, Watcher 内部类 DisconnectReason CloseRequestException EndOfStreamException(流关闭) 属性 方法 getSessionTimeout 获取session失效时间 sendResponse 发送回复数据 se......

writeademo
55分钟前
4
0
如何将 Redis 用于微服务通信的事件存储

来源:Redislabs 作者:Martin Forstner 翻译:Kevin (公众号:中间件小哥) 以我的经验,将某些应用拆分成更小的、松耦合的、可协同工作的独立逻辑业务服务会更易于构建和维护。这些服务(也...

中间件小哥
58分钟前
5
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部