`
zzproc
  • 浏览: 16525 次
  • 性别: Icon_minigender_1
  • 来自: 杭州
社区版块
存档分类
最新评论

Java函数参数传递方式详解

 
阅读更多
在阅读本文之前,根据自己的经验和理解,大家可以先思考并选择一下Java函数的参数传递方式:
A. 是按值传递的?
B. 按引用传递的?
C. 部分按值部分按引用?
此处暂不宣布正确答案,我们通过一个简单的例子让大家自己找答案:
1. 先定义一个类型Value
public static class Value {
	private String value = "value";
	public String getValue() { return value; }
	public void setValue(String value) { this.value = value; }
}

2. 写两个函数newValue和modifyValue:newValue会将入参指向一个新的对象,modifyValue会调用入参的setValue方法修改对象的value值。
public static void newValue(Value value) {
	value = new Value();
	value.setValue("new value");
	System.out.println("In newValue, HashCode = " + value.hashCode() + ", value = " + value.getValue());
}
	
public static void modifyValue(Value value) {
	value.setValue("new value");
	System.out.println("In modifyValue, HashCode = " + value.hashCode() + ", value = " + value.getValue());
}

3. 简单的测试代码
public static void main(String[] args) {
	Value value1 = new Value();
	System.out.println("Before modify, HashCode = " + value1.hashCode() + ", value = " + value1.getValue());
	// 将value1指向新的Value对象
	newValue(value1);
	System.out.println("After modify, HashCode = " + value1.hashCode() + ", value = " + value1.getValue() + "\n");
	Value value2 = new Value();
	System.out.println("Before modify, HashCode = " + value2.hashCode() + ", value = " + value2.getValue());
	// 使用object的set方法,修改对象的内部值
	modifyValue(value2);
	System.out.println("After modify, HashCode = " + value2.hashCode() + ", value = " + value2.getValue());
}

4. 执行结果日志:
Before modify, HashCode = 12677476, value = value
In newValue, HashCode = 33263331, value = new value
After modify, HashCode = 12677476, value = value

Before modify, HashCode = 6413875, value = value
In modifyValue, HashCode = 6413875, value = new value
After modify, HashCode = 6413875, value = new value


5. 结果分析:
上述代码这是非常常见的一种编程模式:在外围定义|保存|获取一个值或对象,将这个对象作为参数传入一个方法,在方法中修改对象的属性、行为。但两个方法newValue和modifyValue的修改方式不一样,在方法调用之后,该对象在外围看来也有很大的差别!如何理解这种差异呢?先温故一下按值传递、按引用传递的概念:
* 按值传递意味着当将一个参数传递给一个函数时,函数接收的是原始值的一个副本。因此,如果函数修改了该参数,仅改变副本,而原始值保持不变。
* 按引用传递意味着当将一个参数传递给一个函数时,函数接收的是原始值的内存地址,而不是值的副本。因此,如果函数修改了该参数,参数的原始值(函数块之外的调用代码中)也随之改变。
正确的答案:A——Java函数是按值传递参数的!
分析一下日志:
* 第一段日志输出,value1参数在newValue方法内部被改为指向新对象,并输出了新对象的hashCode和value值,但跳出newValue方法域之后,在main方法中的value1没有发生任何变化,这符合按值传递的定义和特点;如果是按引用传递,value1在调用newValue(Value value)方法之后,应该是发生变化的。
* 第二段日志输出,value2在modifyValue方法内部进行了setValue操作,hashCode不变而value被修改,离开modifyValue方法域之后,在main方法中value2确实发生了变更。使用过C++的人容易将这种现象理解为:按引用传递函数参数!因为这跟C++中的按引用传递像极了!但这里恰恰是最容易陷入误区的地方!
两段日志的不同现象背后所隐藏的是原理是:Java语言是按值传递参数,按引用传递对象的;Java中所操作的对象其实都是操作对象的引用,object本身保存在“堆”中,而对象的“引用“保存在寄存器或“栈”中。
伪代码描述一下newValue方法和modifyValue方法的不同之处:
newValue{
	Value_ref2 = value_ref1; 	// 按值传入引用value_ref1,得到value_ref1的副本
	value_obj2 = new Value();	// value_obj2被创建、初始化在“堆“中
	value_ref2 -> value_obj2;	// value_ref2 指向value_obj2
value_ref2 ->value_obj2.setValue(“xxx”);	// value_obj2 的value被修改
printValueObj2();			// 此处打印的是obj2的值
}
modifyValue{
	Value_ref2 = value_ref1; 	// 按值传入引用value_ref1,得到value_ref1的副本
value_ref2 ->value_obj1.setValue(“xxx”);	// value_obj1 的value被修改
printValueObj1();			// 此处打印的是obj1的值
}

够清楚了吧!value1_ref1在作为参数传入函数的时候,首先被复制了一份副本value1_ref2供函数域使用,此时这两个ref都是指向同一个value_obj; newObject函数中的代码[ value = new Value(); ] 其实是将value1_ref1指向了一个新的对象value_obj2;在这之后的set操作都是对新对象的操作;modifyValue函数是通过set方法直接操作value_obj1,这是跟newValue函数的不同之处。

如果还是不太明白,请先确定是否已经理解 “引用”、“对象”的概念,可以Google、百度相应的文章学习一下:)
分享到:
评论

相关推荐

    java 中函数的参数传递详细介绍

    主要介绍了 java 中函数的参数传递详细介绍的相关资料,需要的朋友可以参考下

    java 与C语言传递结构体数据

    描述:为了解决java与C结构通信过程中结构体解析问题。 主要功能:能友好的用java处理任何发送的C结构体对象,并且能发送java对象转换成C结构体接收的二进制。 功能说明 1、基于spring框架开发 2、对于结构体定义...

    《Java和Android开发实战详解》第2到5章源代码-by 南邮-陈杨

    5.2.2 类方法的参数传递 81 5.2.3 类方法的返回值 83 5.2.4 值传递与引用传递 84 5.3 类变量和变量作用域 86 5.3.1 Java的类变量 86 5.3.2 Java的变量作用域 87 5.4 递归程序设计 89 5.4.1 递归方法...

    java8传函数方法图文详解

    在本篇文章中小编给大家整理了关于java8传函数方法和相关知识点,需要的朋友们学习下。

    详解javascript函数的参数

    因为函数是弱类型的,没有方法去声明它所期望的参数类型,并且给任何函数传递任何类型的值都是合法的。 1.Js函数可以传入不同的参数,如 function writeNString(strMsg){ [removed](strMsg + " "); } 2.Js函数...

    javascript 回调函数详解

    在JavaScript中,回调函数具体的定义为:函数A作为参数(函数引用)传递到另一个函数B中,并且这个函数B执行函数A。我们就说函数A叫做回调函数。如果没有名称(函数表达式),就叫做匿名回调函数。因此callback 不一定...

    JNA 转java接口以及指针结构体解析

    经过几天的奋战,终于让我搞懂了JNA的解析以及指针在结构体中的应用!!!下了很多的资料,里面包含c++的.h头文件,给需要帮助的人看看!! 里面包含代码以及解析过程。

    Java中支持可变参数详解

    那个可变参数的就是个数组,你传多少个参数都被放到那个数组里面。这样方便了程序员,因为如果不确定要传的参数的个数的话,我们要写带1个参数的,带... 该进后的这个方法,我们只要写一个函数就好,可以传任意个参数。

    Java开发技术大全(500个源代码).

    invokeByObject.java 对象实参传递示例程序 invokeByValue.java 传值调用示例程序 invokeMethod.java 同一个类中调用方法示例 invokeOther.java 类的外部调用方法示例 invokeStaticMethod.java 调用静态方法...

    java的传值与传引用详解

     C 语言中有一种数据类型叫做指针,于是将一个数据作为参数传递给某个函数的时候,就有两种方式:传值,或是传指针,它们的区别,可以用一个简单的例子说明: /* 例 5 */ /** * @(#) test.c * @author fancy */...

    java的类别方法(格式:PPT 字体:繁体)

    Java方法的参数列是资讯传递的机制,可以从外面将资讯送入程序的黑盒子,参数列是方法的使用介面. 一个方法如果拥有参数列,在呼叫方法时,传入不同的参数就可以产生不同的执行结果. 4-3-2 类别方法的参数传递-范例 例如...

    详解Python传入参数的几种方法

    Python唯一支持的参数传递方式是『共享传参』(call by sharing) 多数面向对象语言都采用这一模式,包括Ruby、Smalltalk和Java(Java的引用类型是这样,基本类型按值传递) 共享传参是指函数的各个形式参数获得实参...

    Java核心技术II(第8版)

    第一章 流与文件 1.1 流 1.1.1 读入和写出字节 1.1.2 完整的流家族 1.1.3 组合流过滤器 1.2 文本输入与输出 1.2.1 如何写出文本输出 1.2.2 如何读入文本输入 ...12.10.3 以本地方法方式实现注册表访问函数

    详解JavaScript的回调函数

    因为function实际上是一种对象,它可以“存储在变量中,通过参数传递给(别一个)函数(function),在函数内部创建,从函数中返回结果值”。 因为function是内置对象,我们可以将它作为参数传递给另一个函数,延迟到...

    Table_map_log_event内容详解.pdf

    本书的主要内容如下: Java 8实战目录第一部分 基础知识 第1章 为什么要关心Java 8 2 第2章 通过行为参数化传递代码 20 第3章 Lambda表达式 34 第二部分 函数式数据处理 第4章 引入流 68 第5章 使用流 82 ...

    javascript some()函数用法详解

    参数说明 callback: 要对每个数组元素执行的回调函数。 thisObject : 在执行回调函数时定义的this对象。 ...如参数 thisObject 被传递进来,它将被当做回调函数(callback)内部的 this 对象,如

    java面试800题

    Java基本类型的都是值传递,对象使用的都是引用传递 Q0043 java相关概念 "static:静态,无需实例化,可直接引用,全局只有一份copy,修饰变量和方法 final:最终的,不可继承、不可修改,修饰变量、方法、类 ...

    疯狂JAVA讲义

    5.2.2 方法的参数传递机制 116 5.2.3 形参长度可变的方法 120 5.2.4 递归方法 121 5.2.5 方法重载 123 学生提问:为什么方法的返回值类型不能用于区分重载的方法? 124 5.3 成员变量和局部变量 124 5.3.1 成员...

    java核心面试技术点

    每条线程都有自己的工作内存(Working Memory),工作内存中保存的是主存中某些对象成员变量的拷贝,线程对所有对象成员变量的操作都是在工作内存中进行,线程之间无法相互直接访问,变量传递均需要通过主存完成。...

Global site tag (gtag.js) - Google Analytics