Java函数参数传递方式详解

在阅读本文之前,根据自己的经验和理解,大家可以先思考并选择一下Java函数的参数传递方式: 
A. 是按值传递的? 
B. 按引用传递的? 
C. 部分按值部分按引用? 
此处暂不宣布正确答案,我们通过一个简单的例子让大家自己找答案: 
1. 先定义一个类型Value

Java代码  

  1. public static class Value {
  2. private String value = "value";
  3. public String getValue() { return value; }
  4. public void setValue(String value) { this.value = value; }
  5. }

2. 写两个函数newValue和modifyValue:newValue会将入参指向一个新的对象,modifyValue会调用入参的setValue方法修改对象的value值。

Java代码  

  1. public static void newValue(Value value) {
  2. value = new Value();
  3. value.setValue("new value");
  4. System.out.println("In newValue, HashCode = " + value.hashCode() + ", value = " + value.getValue());
  5. }
  6. public static void modifyValue(Value value) {
  7. value.setValue("new value");
  8. System.out.println("In modifyValue, HashCode = " + value.hashCode() + ", value = " + value.getValue());
  9. }

3. 简单的测试代码

Java代码  

  1. public static void main(String[] args) {
  2. Value value1 = new Value();
  3. System.out.println("Before modify, HashCode = " + value1.hashCode() + ", value = " + value1.getValue());
  4. // 将value1指向新的Value对象
  5. newValue(value1);
  6. System.out.println("After modify, HashCode = " + value1.hashCode() + ", value = " + value1.getValue() + "\n");
  7. Value value2 = new Value();
  8. System.out.println("Before modify, HashCode = " + value2.hashCode() + ", value = " + value2.getValue());
  9. // 使用object的set方法,修改对象的内部值
  10. modifyValue(value2);
  11. System.out.println("After modify, HashCode = " + value2.hashCode() + ", value = " + value2.getValue());
  12. }

4. 执行结果日志:

Java代码  

  1. Before modify, HashCode = 12677476, value = value
  2. In newValue, HashCode = 33263331, value = new value
  3. After modify, HashCode = 12677476, value = value
  4. Before modify, HashCode = 6413875, value = value
  5. In modifyValue, HashCode = 6413875, value = new value
  6. 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方法的不同之处:

Java代码  

  1. newValue{
  2. Value_ref2 = value_ref1;    // 按值传入引用value_ref1,得到value_ref1的副本
  3. value_obj2 = new Value();   // value_obj2被创建、初始化在“堆“中
  4. value_ref2 -> value_obj2;    // value_ref2 指向value_obj2
  5. value_ref2 ->value_obj2.setValue(“xxx”); // value_obj2 的value被修改
  6. printValueObj2();           // 此处打印的是obj2的值
  7. }
  8. modifyValue{
  9. Value_ref2 = value_ref1;    // 按值传入引用value_ref1,得到value_ref1的副本
  10. value_ref2 ->value_obj1.setValue(“xxx”); // value_obj1 的value被修改
  11. printValueObj1();           // 此处打印的是obj1的值
  12. }

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

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

时间: 2024-10-10 13:49:31

Java函数参数传递方式详解的相关文章

函数参数传递方式详解

1. 函数参数传递方式之一:值传递 (1)值传递的一个错误认识 先看如下的一个问题: void Exchg1(int x, int y) /* 定义中的x,y变量被称为Exchg1函数的形式参数 */ { int tmp; tmp = x; x= y; y= tmp; printf("x = %d, y = %d.\n", x, y); } 问:你认为这个函数是在做什么呀? 答:好像是对参数x.y的值对调吧? 请往下看,我想利用这个函数来完成对a,b两个变量值的对调,程序如下: mai

二维数组作为函数参数深度详解

        前几天和同学讨论数组作为函数参数,感觉各种困惑.花了一些时间在网上查看了一些资料,并加上自己的理解.记录一下! 一. 指向指针的指针和指向数组的指针 很多人以为"指向数组的指针"就是"指向指针的指针",于是有人写这样的代码: int a[3][4]; int **p = a; //错误 数组实际类型是int [3][4],在作为右值时可以被转化为int (*)[4],它们都和int **不同,自然不可用. 那么,你要用一个指针来指向a,就要用一个

基于.Net Framework 4.0 Web API开发(2):ASP.NET Web APIs 参数传递方式详解

概述:  ASP.NET Web API 的好用使用过的都知道,没有复杂的配置文件,一个简单的ApiController加上需要的Action就能工作.调用API过程中参数的传递是必须的,本节就来谈谈API使用过程中参数的传递方式. 各种参数传递方式的实现: ASP.NET Web API参数有两种传递方式,一种是请求时携带QueryString,对应API 开发中的FromUrlAttribute属性,也是参数传递默认属性,并且每个API可以含有多个此类型的参数,主要应对GET请求,但此种方式

java JVM 参数实例详解

http://www.pinterest.com/fjjrn/%E8%BE%BD%E9%98%B3%E6%89%BE%E5%B0%8F%E5%A7%90/ http://www.pinterest.com/99f99pn9j9/%E9%93%81%E5%B2%AD%E6%89%BE%E5%B0%8F%E5%A7%90/ http://www.pinterest.com/fbbhjz/%E8%90%A5%E5%8F%A3%E6%89%BE%E5%B0%8F%E5%A7%90/ http://www

java虚拟机启动参数分类详解

官方文档见: http://docs.sun.com/source/819-0084/pt_tuningjava.html java启动参数共分为三类:其一是标准参数(-),所有的JVM实现都必须实现这些参数的功能,而且向后兼容:其二是非标准参数(-X),默认jvm实现这些参数的功能,但是并不保证所有jvm实现都满足,且不保证向后兼容:其三是非Stable参数(-XX),此类参数各个jvm实现会有所不同,将来可能会随时取消,需要慎重使用: 一.标准参数中比较有用的: verbose -verbo

java newInstance() 的参数版本与无参数版本详解

newInstance() 的参数版本与无参数版本详解 博客分类: Core Java 通过反射创建新的类示例,有两种方式: Class.newInstance() Constructor.newInstance() 以下对两种调用方式给以比较说明: Class.newInstance() 只能够调用无参的构造函数,即默认的构造函数: Constructor.newInstance() 可以根据传入的参数,调用任意构造构造函数. Class.newInstance() 抛出所有由被调用构造函数抛

Java中InvocationHandler接口中第一个参数proxy详解

java动态代理机制中有两个重要的类和接口InvocationHandler(接口)和Proxy(类),这一个类Proxy和接口InvocationHandler是我们实现动态代理的核心: 1.InvocationHandler接口是proxy代理实例的调用处理程序实现的一个接口,每一个proxy代理实例都有一个关联的调用处理程序:在代理实例调用方法时,方法调用被编码分派到调用处理程序的invoke方法. 看下官方文档对InvocationHandler接口的描述: {@code Invocat

夯实JAVA基本之一 —— 泛型详解(1)

前言:无论何时,相信自己. 相关文章: 1.<夯实JAVA基本之一 -- 泛型详解(1)>2.<夯实JAVA基本之一 -- 泛型详解(2)> 一.引入 1.泛型是什么 首先告诉大家ArrayList就是泛型.那ArrayList能完成哪些想不到的功能呢?先看看下面这段代码: ArrayList<String> strList = new ArrayList<String>(); ArrayList<Integer> intList = new A

Scala 深入浅出实战经典 第60讲:Scala中隐式参数实战详解以及在Spark中的应用源码解析

王家林亲授<DT大数据梦工厂>大数据实战视频 Scala 深入浅出实战经典(1-87讲)完整视频.PPT.代码下载:百度云盘:http://pan.baidu.com/s/1c0noOt6 腾讯微云:http://url.cn/TnGbdC 360云盘:http://yunpan.cn/cQ4c2UALDjSKy 访问密码 45e2土豆:http://www.tudou.com/programs/view/IVN4EuFlmKk/优酷:http://v.youku.com/v_show/id_