`
ayaoxinchao
  • 浏览: 80439 次
  • 性别: Icon_minigender_1
  • 来自: 合肥
社区版块
存档分类
最新评论

Java函数调用方式——按值传递

阅读更多

Java使用按值传递的函数调用方式,这往往使我感到迷惑。因为在基础数据类型和对象的传递上,我就会纠结于到底是按值传递,还是按引用传递。其实经过学习,Java在任何地方,都一直发挥着按值传递的本色。

 

首先,让我们看一看基础数据类型是如何按值传递的。

 

public static void main(String[] args) {
		
	int a = 2;
	calculate(a);
	System.out.println(a);
	
}

public static void calculate(int param) {
	param += 3;
	System.out.println(param);
}

 输出结果为:

5
2

 这样的结果根据按值传递,并不难理解。

 

 

其次,让我们来看看复杂的对象时如何保持自己的“贞操”,而仅仅是把引用这个“才艺”展示给人们。

 

public static void main(String[] args) {
    // 包装类型,不可变类型	
	Integer b = new Integer(2);
	calculate2(b);
	System.out.println(b);
	
    // 日期类型,目标方法改变对象值,当前日期2013-09-24
	Date d1 = new Date();
	claculate3(d1);
	System.out.println(d1);
		
    // 日期类型,目标方法仅读取对象值,当前日期2013-09-24
	Date d2 = new Date();
	calculate4(d2);
	System.out.println(d2);
}
	
public static void calculate2(Integer param) {
	param += 3;
	System.out.println(param);
}
	
public static void claculate3(Date date) {
	date.setDate(date.getDate() + 1);
	System.out.println(date);
}
	
public static void calculate4(Date date) {
	date = new Date(date.getYear(), date.getMonth(), date.getDate() + 1);
	System.out.println(date);
}

 输出结果为:

5
2
Wed Sep 25 20:24:32 CST 2013
Wed Sep 25 20:24:32 CST 2013
Wed Sep 25 00:00:00 CST 2013
Tue Sep 24 20:24:32 CST 2013

 从结果可以看出:

 

一、包装类型作为不可变的对象,原有的Integer对象并没有改变,所以输出与基础类型的一样。

二、日期类型是可变对象,当仅仅是读取原有对象中的值时,没有问题,调用函数中的打印结果不改变,和当前日期保持一致,只是目标函数中打印的是新对象的值,所以两次打印结果不同;当在目标方法中将原有对象改变,那么两次打印的都是原有对象的值,所以结果相同,并且与初始的new Date()不一样。

 

所以说呢,基础数据类型按值传递很容易理解,但是对于对象,Java也是按值传递,只不过传递的时候不是直接传递对象,而是传递引用的值,引用指向的对象相同而已。

 

以我的水平就能写这么多,希望大牛们觉得不对的地方,给我指出来。。。

1
2
分享到:
评论
6 楼 arthur8 2013-09-25  
JLS上已经明确写了java是值传递~
5 楼 luoyu-ds 2013-09-25  
longshaojian 写道
ayaoxinchao 写道
longshaojian 写道
对于函数调用的参数传递为对象传递时是否可以这样理解:
在方法调用栈上首先创建了一个引用[暂且称其为 StackObject]指向与参数相同的对象地址,这时候区分两个测试方法内部过程可以理解为:

   calculate3 是 改变StackObject 所指向的对象的属性,因为这个所指向的对象与传递到函数的参数对象是同一个,因此改变是受影响的。
   calculate4 是 将 StackReferece 重新指向了一个新的对象地址,从此之后就它就与传递到函数的对象没有关系了,因此改变不会影响到传递的参数对象。

   博主只要在相应的地方打印各个参数和变量对象的内存地址即可一目了然。

   不知道这么理解对不对了~~

仁兄解释的很透彻,和我表达的意思一样,但是我写的太概念化。有机会还是要对JVM深入了解一下,谢谢!


博主的博文也写的很好。其实很凑巧,昨天下午我自己也刚好测试了关于 Integer 包装类型的方法参数传递,结果居然不是意想中的对象值改变,也让我小惊喜了一把,到晚上偶然看到你的博文,大惊咱两居然同一天在测试统一个问题,真是有缘,哈哈。

你俩就搞基吧
4 楼 longshaojian 2013-09-25  
ayaoxinchao 写道
longshaojian 写道
对于函数调用的参数传递为对象传递时是否可以这样理解:
在方法调用栈上首先创建了一个引用[暂且称其为 StackObject]指向与参数相同的对象地址,这时候区分两个测试方法内部过程可以理解为:

   calculate3 是 改变StackObject 所指向的对象的属性,因为这个所指向的对象与传递到函数的参数对象是同一个,因此改变是受影响的。
   calculate4 是 将 StackReferece 重新指向了一个新的对象地址,从此之后就它就与传递到函数的对象没有关系了,因此改变不会影响到传递的参数对象。

   博主只要在相应的地方打印各个参数和变量对象的内存地址即可一目了然。

   不知道这么理解对不对了~~

仁兄解释的很透彻,和我表达的意思一样,但是我写的太概念化。有机会还是要对JVM深入了解一下,谢谢!


博主的博文也写的很好。其实很凑巧,昨天下午我自己也刚好测试了关于 Integer 包装类型的方法参数传递,结果居然不是意想中的对象值改变,也让我小惊喜了一把,到晚上偶然看到你的博文,大惊咱两居然同一天在测试统一个问题,真是有缘,哈哈。
3 楼 ayaoxinchao 2013-09-25  
longshaojian 写道
对于函数调用的参数传递为对象传递时是否可以这样理解:
在方法调用栈上首先创建了一个引用[暂且称其为 StackObject]指向与参数相同的对象地址,这时候区分两个测试方法内部过程可以理解为:

   calculate3 是 改变StackObject 所指向的对象的属性,因为这个所指向的对象与传递到函数的参数对象是同一个,因此改变是受影响的。
   calculate4 是 将 StackReferece 重新指向了一个新的对象地址,从此之后就它就与传递到函数的对象没有关系了,因此改变不会影响到传递的参数对象。

   博主只要在相应的地方打印各个参数和变量对象的内存地址即可一目了然。

   不知道这么理解对不对了~~

仁兄解释的很透彻,和我表达的意思一样,但是我写的太概念化。有机会还是要对JVM深入了解一下,谢谢!
2 楼 longshaojian 2013-09-24  
发现上面的一处纰漏,内存地址不好打印,还是改成 hashcode 吧

添加了 hashcode 的打印之后,就比较明显了



5
2
Wed Sep 25 23:21:31 CST 2013
claculate3 hashCode:	1437989003

Wed Sep 25 23:21:31 CST 2013
d1 hashCode:	1437989003

Wed Sep 25 00:00:00 CST 2013
claculate4 hashCode:	1353898305

Tue Sep 24 23:21:31 CST 2013
d2 hashCode:	1351589027
1 楼 longshaojian 2013-09-24  
对于函数调用的参数传递为对象传递时是否可以这样理解:
在方法调用栈上首先创建了一个引用[暂且称其为 StackObject]指向与参数相同的对象地址,这时候区分两个测试方法内部过程可以理解为:

   calculate3 是 改变StackObject 所指向的对象的属性,因为这个所指向的对象与传递到函数的参数对象是同一个,因此改变是受影响的。
   calculate4 是 将 StackReferece 重新指向了一个新的对象地址,从此之后就它就与传递到函数的对象没有关系了,因此改变不会影响到传递的参数对象。

   博主只要在相应的地方打印各个参数和变量对象的内存地址即可一目了然。

   不知道这么理解对不对了~~

相关推荐

    JNI技术手册 c/c++调用java

    II. java c/cpp互相调用实例(姊妹篇之一)——java调用c/cpp 4 一 先制作一个系统中有的DLL文件(cpp给出的sdk接口) 4 二 JNI 7 1、 编写java文件 7 2、 生成.h头文件 8 3、 用c/cpp实现这个头文件 9 三 测试 10 ...

    JNI函数使用

    代码清单15-10 在Linux平台上调用C函数的例程——Sample3 public class Sample3 { public native String[] stringMethod(String text); public static void main(String[] args) throws java.io....

    java的传值与传引用详解

     结果,就像光到底是波还是粒子的问题一样,Java 方法的参数是按什么传递的问题,其答案就只能是:即是按值传递也是按引用传递,只是参照物不同,结果也就不同。  4. 正确看待传值还是传引用的问题  要正确的...

    Linux C程序设计大全

    3.4.1 函数调用与程序优化 3.4.2 变量存储优化 3.5 编写多文件程序——变量的存储类别 3.5.1 存储类别 3.5.2 static变量的作用——改变变量的生命期 3.5.3 static变量的作用——实现封装和模块化设计 3.6 编写多文件...

    c#学习笔记——学习心得

    向方法传递结构时,是通过传值方式传递的,结构实例化可以不用new,结构可以声明构造函数,但必须带参数,且声明的构造函数是用来对成员初始化的,必须包含每个字段。结构不能从另一个结构或类继承而来,但可以实现...

    android开发——简易计算器的设计报告.doc

    (1)Activity的相关方法及相关函数:void onCreate(Bundle)首次启动时调用,接受参数:Null or savedInstanceState(保存的以前某些状态信息); void onStart() 说明了将要显示给用户的活动;void onRestart()将...

    PHPWeb开发技术指南——pdf格式

    译者序 序言 前言 ...第1章 开发思想 1 ...1.2 计划的重要性 2 1.3 编码规范 3 1.3.1 选择名字 3 1.3.2 使代码更易读 5 1.3.3 添加注释 8 ...9.20 调用用户函数 261 9.21 下一步该做些什么 265 9.22 参考:一些配置宏 265

    javaScript call 函数的用法说明

    call 方法 请参阅 应用于:Function 对象 要求 版本 5.5 调用一个对象的一个方法,以另一个对象替换当前对象。 call([thisObj[,arg1[, arg2[, [,.argN]]]]]) 参数 thisObj 可选项。... ————————————

    超爽的自学课件(java)

    <br>(12) 第12章:传递和返回对象 由于我们在Java中同对象沟通的唯一途径是“句柄”,所以将对象传递到一个函数里以及从那个函数返回一个对象的概念就显得非常有趣了。本章将解释在函数中进出时,什么才是...

    Visual C++ 2010入门经典(第5版)--源代码及课后练习答案

    5.2.1 按值传递机制 216 5.2.2 给函数传递指针实参 217 5.2.3 给函数传递数组 219 5.2.4 给函数传递引用实参 222 5.2.5 使用const修饰符 224 5.2.6 rvalue引用形参 225 5.2.7 main()函数的实参 227 5.2.8 ...

    将 Flex 集成到 Java EE 应用程序的最佳实践(完整源代码)

    不过,针对 Java EE 开发的服务器端应用,可以通过集成 BlazeDS,充分利用 AMF 协议并能轻易与 Flex 前端交换数据,这种方式是 Java EE 应用程序集成 Flex 的首选。 BlazeDS 是 Adobe LifeCycle Data Services 的...

    Visual C++ 2005入门经典--源代码及课后练习答案

    5.4 递归函数调用 239 5.5 C++/CLI编程 241 5.5.1 接受数量可变实参的函数 242 5.5.2 main( )的实参 243 5.6 小结 244 5.7 练习 245 第6章 程序结构(2) 246 6.1 函数指针 246 6.1.1 声明函数指针 ...

    +Flex+集成到+Java+EE+应用程序的最佳实践(完整源代码)

    不过,针对 Java EE 开发的服务器端应用,可以通过集成 BlazeDS,充分利用 AMF 协议并能轻易与 Flex 前端交换数据,这种方式是 Java EE 应用程序集成 Flex 的首选。 BlazeDS 是 Adobe LifeCycle Data Services 的...

    C++大学教程,一本适合初学者的入门教材(part2)

    5.4 按引用调用函数 5.5 指针与常量限定符 5.6 按引用调用的冒泡排序 5.7 指针表达式与指针算法 5.8 指针与数组的关系 5.9 指针数组 5.10 实例研究:洗牌与发牌 5.11 函数指针 5.12 字符与字符串处理简介 ...

    C++大学教程,一本适合初学者的入门教材(part1)

    5.4 按引用调用函数 5.5 指针与常量限定符 5.6 按引用调用的冒泡排序 5.7 指针表达式与指针算法 5.8 指针与数组的关系 5.9 指针数组 5.10 实例研究:洗牌与发牌 5.11 函数指针 5.12 字符与字符串处理简介 ...

    疯狂的java讲义源码-gal-practice-lesson:gal实践课

    个或多个非函数参数的函数。 我们的第一个迭代器:Map 目标 类型 客观的 已申请 在 JavaScript 中使用Array.prototype.map执行基本数据转换。 概念性的 回想一下Array.prototype.map的签名和传递给它的回调。 概念性...

    Python编程入门经典

    5.2.8 在函数中调用其他函数 78 5.2.9 函数嵌套函数 80 5.2.10 用自己的词语标记错误 81 5.3 函数的层次 81 5.4 本章小结 82 5.5 习题 83 第6章 类与对象 85 6.1 考虑编程 85 6.1.1 对象的含义 85 6.1.2 已经了解的...

    在一小时内学会 C#(txt版本)

    如果熟悉 Java 语言,Java 的编程结构、打包和垃圾回收的概念肯定对你快速学习 C# 大有帮助。所以我在讨论 C# 语言构造的时候会假设你知道 C++。 本文通过一系列例程以简短但全面的方式讨论了 C# 语言构造和特性,...

    c#学习笔记.txt

    如果没有ref,out则默认为值传递,虽然可以在方法中修改这个参数的值,但是修改后的值不会还会到调用该方法的程序中. params :params 关键字可以指定在参数数目可变处采用参数的方法参数 ref :引用传递 out : 7, ...

Global site tag (gtag.js) - Google Analytics