`

也谈JAVA值传参和引用传参

    博客分类:
  • Java
阅读更多
这是个老生常谈的问题了,经过了先辈们无数的争论,但是还是没有提出一个令所有人满意的答案。当然,我在这里只是就我自己对Java和其他语言的一些认识谈谈自己的理解和看法。
首先,我们要明确下面这两条不可争论的事实了:
【1】、对象是传引用的
【2】、基本类型是传值的

我对这个问题是这样理解的:
有过C++背景的朋友可能都会有一个认识,因为C/C++传参有很多种选择,直接传递对象或值,或者传递指针,传递引用等。而大家都有个共识,那就是在传递基本数据类型时,选择第一种,而传递对象的时候则选用传指针或者引用。这点可以从数据传输效率的角度上得到解释。
而Java创始人James在某些方面还是得借鉴一些C的思想的,所以上述两条就比较好理解了。
个人对传参的理解是:
函数参数相对其他字段,在编译器里肯定会有特殊处理的,而一般的编译器则是这样处理:
在运行栈中拷贝一份传递过来的参数(值参),而后面函数体的关于值参的操作实际上都是针对运行栈里保存的备份操作的。可以用这种理解验证一下C++的三种情况。例如传递过来的是引用,则编译器的处理流程是这样的:
首先拷贝传递来的值参(注意:值参也是引用,Java里new之后获得的都是对象的引用,而不是对象本身,这点和c++很不同),然后将其压入运行栈,后面的操作也就是对这份拷贝(也是对预期的对象的引用,所以可以到达对象)操作了。

我们看看以下的几个例子来增加对上述思想的理解。

Example1:
package com.shansun.ref;

public class RefInteger {

	public RefInteger() {
	}

	public void swap(Integer para1, Integer para2) {
		Integer tmp;
		tmp = para1;
		para1 = para2;
		para2 = tmp;
	}

	public void print(int int1, int int2) {
		System.out.println("Int1 is " + int1);
		System.out.println("Int2 is " + int2);
	}

	public static void main(String[] args) {
		Integer int1 = new Integer(10);
		Integer int2 = new Integer(50);

		RefInteger ref = new RefInteger();
		System.out.println("---------SWAP UNABLE----------");
		ref.swap(int1, int2);
		ref.print(int1, int2);
	}
}

运行结果:
---------SWAP UNABLE----------
Int1 is 10
Int2 is 50

我们都知道一点:void swap(int, int)是不能达到交换两个参数的值的。我们这里试试使用Integer对象呢?同样也交换失败,原因很简单:void swap(Integer para1, Integer para2)函数传递进来的是两个类型为Integer类的引用,而在函数体里实现的功能只是改变了para1和para2引用的对象,而para1和para2在内存中的值却一点变化都没有。可能这样理解更加形象一点:
例如,A省省长是小王,B省省长是小张,这样牵强的理解为小王是A省的一个引用,小张则是B省的一个引用。在执行swap(小王,小张)后,产生的效果只是:现在A省省长是小张,B省省长是小王了,即现在小张代表的不再是B省,而是A省了,而对于对象本身,如A省,其地理位置,人口数量等都没有变化。不能说在swap语句执行后,A省跑到地图上B省的位置去了吧?

Example2:
package com.shansun.ref;

public class RefObject {

	int val;

	public RefObject(int val) {
		this.val = val;
	}

	public void setVal(int val) {
		this.val = val;
	}

	public int getVal() {
		return this.val;
	}

	public void print() {
		System.out.println("Now val is " + val);
	}

	public static void swap(RefObject obj1, RefObject obj2) {
		RefObject tmp;
		tmp = obj1;
		obj1 = obj2;
		obj2 = tmp;
	}

	public static void swapx(RefObject obj1, RefObject obj2) {
		int tmp;
		tmp = obj1.getVal();
		obj1.setVal(obj2.getVal());
		obj2.setVal(tmp);
	}

	public static void main(String[] args) {
		RefObject obj1 = new RefObject(10);
		RefObject obj2 = new RefObject(50);
		obj1.print();
		obj2.print();
		swap(obj1, obj2);
		obj1.print();
		obj2.print();
		swapx(obj1, obj2);
		obj1.print();
		obj2.print();
	}
}

执行结果:
---------SWAP UNABLE----------
Int1 is 10
Int2 is 50
---------BEFORE SWAP----------
Int1 is 20
Int2 is 30
---------SWAP ENABLE----------
Int1 is 30
Int2 is 20

首先和上面例子一样,swap(obj1, obj2)也是换汤不换药的,所以交换失败。但是swapx则交换数据成功了,我们还拿上面省长的例子来解释这个现象:
国家要求小王代表的A省的C市市长和小张代表的B省的D市市长交换职位,可以吗?当然可以了,所以交换成功。

我们最后再回到Example1的问题,如果我就想交换两个int值呢?其实也不是没有办法的。
package com.shansun.ref;

public class RefInteger {

	int int1, int2;

	public RefInteger(int int1, int int2) {
		this.int1 = int1;
		this.int2 = int2;
	}

	public void swap() {
		int tmp;
		tmp = int1;
		int1 = int2;
		int2 = tmp;
	}

	public void print() {
		System.out.println("Int1 is " + int1);
		System.out.println("Int2 is " + int2);
	}

	public static void main(String[] args) {
		RefInteger ref = new RefInteger(20, 30);
		System.out.println("---------BEFORE SWAP----------");
		ref.print();
		System.out.println("---------SWAP ENABLE----------");
		ref.swap();
		ref.print();
	}
}


执行结果:
---------BEFORE SWAP----------
Int1 is 20
Int2 is 30
---------SWAP ENABLE----------
Int1 is 30
Int2 is 20

小记:
C++:使用分界符&标示引用
C#: 使用ref关键字标示引用

好了,关于传参的问题我的理解就是这样的。如有错误,敬请指出。

6
0
分享到:
评论

相关推荐

    java 之方法调用 方法传参 值传递还是引用传递字节码

    本文将深入探讨Java中的方法调用、值传递与引用传递,并通过字节码分析来进一步理解这些概念。 首先,我们来看方法调用。在Java中,方法是一组完成特定任务的代码块,可以通过方法名来调用执行。方法调用的基本语法...

    Java传参方式-值传递还是引用传递

    2. Java 仅支持按值传递参数,无论是基本类型还是引用类型。 3. 按值传递意味着方法内部的任何修改都不会影响到原始参数的值,除非是修改引用所指向的对象的状态。 4. 对于基本类型,传递的是原始值的拷贝,而对引用...

    java jni 引用传参方法

    可传入引用参数类型为:句柄,string, int

    引用类型传值方法

    在编程领域,我们经常需要处理各种数据类型,其中包括值类型(value types)和引用类型(reference types)。值类型如整型、浮点型、布尔型等,它们在赋值或作为参数传递时会进行副本复制,而引用类型则有所不同。本...

    浅析java中Integer传参方式的问题

    在Java编程语言中,参数传递主要有两种方式:值传递和引用传递。然而,Java只支持值传递,这里的“值”可以是基本类型(如int)的直接值,或者是对象的引用(即对象在内存中的地址)。当我们谈论Integer类型的参数...

    Java开启新线程并传参方法代码实现

    "Java开启新线程并传参方法代码实现" Java开启新线程并传参方法...本文详细介绍了Java开启新线程并传参方法代码实现的两种方式:继承Thread类和实现Runnable接口。希望对大家的学习有所帮助,也希望大家多多支持我们。

    java通过实例了解值传递和引用传递

    java通过实例了解值传递和引用传递 Java语言中有两种基本的参数传递方式:值传递和引用传递。值传递是指在方法调用时,传递的参数是按值的拷贝传递。引用传递是指在方法调用时,传递的参数是按引用进行传递,其实...

    python-引用传参.docx

    在Python中,由于变量实际上是对象的引用,而不是对象本身,因此即使是"引用传递",也与C++或Java等语言中的引用传递有所区别。 以下是一个关于Python引用传递的例子: ```python def change_list(list): list....

    Java中数组的创建与传参方法(学习小结)

    总之,Java中的数组创建涉及声明和分配内存,而数组参数传递是通过值传递进行的,即传递数组的引用。了解这些基础知识对于编写高效、可维护的Java程序至关重要。希望本文提供的信息对你的学习有所帮助,如有任何疑问...

    java语言中的参数传递

    Java 有两类参数传递方式:按值传递(by value)和按引用传递(by reference),虽然 Java 没有真正的按引用传递,但其效果类似于 C++ 或 C# 中的引用传递。 1. **按值传递(by value)**: - 适用于基本数据类型...

    java参数传递学习demo

    java的参数传递对比,体现了值传递和引用传递的区别,是我在java入门是写的学习demo

    java远程方法调用

    ### Java远程方法调用(RMI):深入解析与实践 #### 一、RMI概念与原理 Java远程方法调用(Remote Method Invocation,简称RMI)是Java平台提供的一种分布式计算模型,允许一个Java虚拟机(JVM)上的对象通过网络...

    浅析Java方法传值和传引用问题

    在`stringBufferUpd`方法中,`bb`对象被传递给方法后,方法内部通过引用修改了`StringBuffer`对象的内容,所以`bb`的值在`main`方法中也发生了变化,输出为"javac"和"javac"。 这种传引用的行为有时会引发混淆,...

    intent 跳转实现activity之间传参

    在Android应用开发中,Intent是连接应用程序组件的重要桥梁,它用于启动新的Activity或者Service,同时也可以在组件间传递数据。本篇文章将详细讲解如何通过Intent实现Activity之间的参数传递。 一、Intent的基本...

    jsp中调用js中的一个函数,函数传参的问题

    这里的`<%= someValueFromBackend %>`和`<%= anotherValue %>`是JSP表达式,它们会在服务器端被Java代码替换为实际值。 3. **传递参数**: JSP表达式`<%= ... %>`允许我们在JavaScript中注入Java变量的值。这些...

    通过字节码看java中this的隐式传参详解

    Java中的隐式传参详解 通过字节码看Java中的this隐式传参是Java语言中一...通过字节码分析可以看到,Java类文件中的每个方法都对应着一个Methodref项,方法调用过程也可以分为方法查找、方法解析和方法调用三个步骤。

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

    JNA还支持自定义结构体类型映射,如`ByReference`和`ByValue`,它们分别用于传递结构体的引用和值。对于指针,JNA提供了一个`Pointer`类,它可以指向任何类型的数据,包括结构体。例如,如果你有一个接收结构体指针...

    调用webservice,通过post传参读取返回的XML

    `Bin`目录则存放编译后的程序集,包括项目引用的库和自定义组件。 通过整合这些元素,我们可以构建一个Web应用程序,该应用程序能够通过POST方式调用WebService,传递参数,并解析返回的XML数据,以便在页面上展示...

    接收弹出页面的回传值

    在事件处理函数中,我们可以获取需要回传的值,并通过`window.opener`属性与A页面进行通信,因为`window.opener`引用了创建当前窗口的窗口对象。例如: ```javascript window.addEventListener('beforeunload', ...

Global site tag (gtag.js) - Google Analytics