如何理解Java中参数传递只能传值?
以前学习C#的时候,是完全在工作岗位上学习,一些底层较为深入的道理都不是很清楚。如今学习了Java,对于Java参数传递只能传值,不能传引用(指针)感到很困惑,在C#中不是常常说把某个引用传递到函数中吗?甚至C#有相当简便的ref、out参数,明明白白的传引用。
经过一番探索,得出的结论表明,Java中我不管你到底是传值还是传引用,只需要记住原生数据类型(值类型)和String作为参数传递的时候,其原本的值都不会发生改变;而引用类型在作为参数传递时,函数中对其的操作,都会反馈到引用所指向的值。
这个结论不是和C#一模一样嘛,除了C#可以方便的使用ref、out以外……
下面对Java中参数传递只能传值进行解释,事实证明,以前我对于C#的传值还是传引用理解的也不够深入:
先申明:java中的参数传递都是值传递,没有引用传递。
值传递的概念:值传递会为所传递的对象(这里的对象不是java里的对象object,而是一般意义上的对象)重新开辟一块空间,于是对所传对象的操作不会影响到原对象。
现象:有种说法是java中基本数据类型作参数是值传递,对象做参数是引用传递。实际上是错误的,真正的引用传递,是类似C语言中的指针传递,和C#中的ref参数。
理解:为什么对象做参数也是值传递呢?
分析:对象做参数传递的是对象的引用,暂且可以理解成对象的地址。由于是值传递,那么被传递的对象本身是不会有任何变化的,所以该对象的引用是不会发生任何变化的。
1、先举一个原生数据类型的例子:
测试函数:
public static void ValueTrans(int a){
a = 2;//新产生一个值,开辟一个值类型出来,故值不会被修改。
}
测试此函数的代码:
int a = 1;
System.out.println("a's value(before) = " + a);
ValueTrans(a);
System.out.println("a's value(after) = " + a);
打印出的结果:
a's value(before) = 1
a's value(after) = 1
安装Java值传递的思想来考虑,这个结果是显而易见的,pass by value,我只是把这个数值传给你使用。
2、那么Integer如何理解呢?
测试函数:
public static void ValueTrans2(Integer a){
a = new Integer(2);
}
其中a也是一个对象,那么这么传入,是不是传引用呢?调用了这个函数,a的int值会不会被修改呢?
测试此函数的代码:
Integer a2 = new Integer(1);
System.out.println("a2's value(before) = " + a2);
ValueTrans2(a2);
System.out.println("a2's value(after) = " + a2);
打印出的结果:
a2's value(before) = 1
a2's value(after) = 1
结果表明,值仍旧没有被修改。
如何解释这个现象:
理解这里的关键是区分对象和引用。这里声明的a2是一个引用,而不是一个对象(只是Java把它设计为看上去好像是对象一样)。这个引用它指向了一个对象,这个对象就是后面用new关键字生成的对象。因此,可以说a2指向了一个Integer对象。
在调用ValueTrans2方法的时候,程序将a2作为参数传递给ValueTrans2方法了。这里仍然是值传递,在ValueTrans2调用过程中,会产生一份新的引用(不妨叫做y)。此时,a2和y指向了同一个对象。
但是此时,我们让y指向另外一个对象, y=new Integer(2); 此时a2和y就指向了不同的对象。y修改了它指向的对象的属性,很显然不会影响到a2指向的对象。
(这里不妨说明一下引用类型的传递,如我把一个引用类型x传入函数中,这里也是值传递,在函数被调用的过程中,产生了一个新的引用y,x和y指向同一个对象。此时修改y指向的对象,也即修改x所指向的对象!那么引用类型的传递,会造成x所指向的值被修改)
图解如下:

3、如何理解String?
如果你理解了2当中Integer的传递方式,那么我想String也不难理解。我们新建一个String,
String string = "old String";
实际上就是
String string2 = new String("old String");
Java的机制,造成当你使用一个String如"old String"时,会新建一个对象出来。
本着负责任的态度,仍旧把相应的测试函数贴上来:
public static void StringTrans(String string){
string = "new String";
}
测试函数的代码:
String string = "old String";
System.out.println("string's value(before) = " + string);
StringTrans(string);
System.out.println("string's value(after) = " + string);
打印出的结果:
string's value(before) = old String
string's value(after) = old String
原因就是,实际上函数StringTrans是复制了一个引用指向原来的对象,但是函数又让这个引用指向了新的String对象。这不会对原来的引用和原来的对象造成任何影响!
4、如何理解引用类型是传值?
测试自定义类:
public class People {
public int age;
public String name;
public People(int age, String name){
this.age = age;
this.name = name;
}
}
测试的函数:
public static void ReferTrans(People people){
people.age = 2;
people.name = "lisi";
}
测试函数的代码:
People people = new People(1, "zhangsan");
System.out.println("people's age(before) = " + people.age);
System.out.println("people's name(before) = " + people.name);
ReferTrans(people);
System.out.println("people's age(after) = " + people.age);
System.out.println("people's name(after) = " + people.name);
打印的结果:
people's age(before) = 1
people's name(before) = zhangsan
people's age(after) = 2
people's name(after) = lisi
设新建的对象是PEOPLE,其引用是people,在调用ReferTrans方法是,仍然是值传递,方法赋值了一个引用people2,people2仍旧指向PEOPLE,所以操作people2对对象进行修改,即为对PEOPLE进行修改(String的话在此时已经new了一个新对象出来),和使用people的效果一样。表现出现来现象就是,当引用类型传入函数时,函数中对其的修改,都会表现在原来的引用类型上。
图解如下:

我一直认为只给分析过程,不给结论的都是耍流氓的行为。
结论:
1、在实际的使用过程中,我们不必纠结那么多,原生数据类型和String,在传入函数的时候,不管函数里面做什么,他的值都不会被修改。引用类型传递到函数中,只要函数中不是让参数指向一个新建的对象,那么函数中的修改会反映到此引用类型上。
2、平时的处理上,可以把String和原生数据类型放在同一类的情况下使用,因为Java内部使用了很多的机制,让String看起来跟原生数据类型一样。但是String归根结底是一个引用类型,如在进行比较时,其他原生数据类型可以使用==,而String必须使用equals方法才能比较其内部的值(这点C#做的非常好,直接使用==,不让程序员过分的了解底层,我在做C#编程的过程中,甚至从来都没有觉得string和值类型有什么不同)。
3、Java确实是只能传值,不能传引用。所谓传引用,只在C、C++的传指针和C#的ref中存在。
如何理解Java中参数传递只能传值?的更多相关文章
- 深入理解Java中的IO
深入理解Java中的IO 引言: 对程序语言的设计者来说,创建一个好的输入/输出(I/O)系统是一项艰难的任务 < Thinking in Java > 本文的目录视图如下: ...
- 理解Java中的ThreadLocal
提到ThreadLocal,有些Android或者Java程序员可能有所陌生,可能会提出种种问题,它是做什么的,是不是和线程有关,怎么使用呢?等等问题,本文将总结一下我对ThreadLocal的理解和 ...
- JDK学习---深入理解java中的LinkedList
本文参考资料: 1.<大话数据结构> 2.http://blog.csdn.net/jzhf2012/article/details/8540543 3.http://blog.csdn. ...
- 【Java】深入理解Java中的spi机制
深入理解Java中的spi机制 SPI全名为Service Provider Interface是JDK内置的一种服务提供发现机制,是Java提供的一套用来被第三方实现或者扩展的API,它可以用来启用 ...
- 深入理解Java 中SPI 制
深入理解Java 中SPI 制 概述 SPI(Service Provider Interface),是JDK内置的一种服务提供发现机制,可以用来启用框架扩展和替换组件,主要是被框架的开发人员使用,比 ...
- 理解Java中的弱引用(Weak Reference)
本篇文章尝试从What.Why.How这三个角度来探索Java中的弱引用,理解Java中弱引用的定义.基本使用场景和使用方法.由于个人水平有限,叙述中难免存在不准确或是不清晰的地方,希望大家可以指出, ...
- 深刻理解Java中final的作用(一):从final的作用剖析String被设计成不可变类的深层原因
声明:本博客为原创博客,未经同意,不得转载!小伙伴们假设是在别的地方看到的话,建议还是来csdn上看吧(原文链接为http://blog.csdn.net/bettarwang/article/det ...
- [译]线程生命周期-理解Java中的线程状态
线程生命周期-理解Java中的线程状态 在多线程编程环境下,理解线程生命周期和线程状态非常重要. 在上一篇教程中,我们已经学习了如何创建java线程:实现Runnable接口或者成为Thread的子类 ...
- Java中参数传递问题
Java中参数传递可以分为值传递和引用传递,话不多说直接撸代码 1.传原始类型(int,String等)数据是值传递 package test_1; public class Test { publi ...
随机推荐
- 【牛客挑战赛30D】小A的昆特牌(组合问题抽象到二维平面)
点此看题面 大致题意: 有\(S\)张无编号的牌,可以将任意张牌锻造成\(n\)种步兵或\(m\)种弩兵中的一种,求最后步兵数量大于等于\(l\)小于等于\(r\)的方案数. 暴力式子 首先我们来考虑 ...
- POJ 1416 Shredding Company【dfs入门】
题目传送门:http://poj.org/problem?id=1416 Shredding Company Time Limit: 1000MS Memory Limit: 10000K Tot ...
- Android学习笔记_72_Spinner的用法
一.普通 1. <?xml version="1.0" encoding="utf-8"?> <TextView xmlns:android= ...
- Android学习笔记_36_ListView数据异步加载与AsyncTask
一.界面布局文件: 1.加入sdcard写入和网络权限: <!-- 访问internet权限 --> <uses-permission android:name="andr ...
- JavaEE权限管理系统的搭建(六)--------使用拦截器实现菜单URL的跳转权限验证和页面的三级菜单权限按钮显示
本小结讲解,点击菜单进行页面跳转,看下图,点击管理员列表后会被认证拦截器首先拦截,验证用户是否登录,如果登录就放行,紧接着会被权限验证拦截器再次拦截,拦截的时候,会根据URL地址上找到对应的方法,然后 ...
- mysql 复制A表 到B表;insert into select * from table
情况一: INSERT INTO tb1 (a,b,c) select a1,b1,c1, from tb2 where .... -- 案例 百度云 INSERT INTO l_biz_car_o ...
- JSTL&EL
JSTL <1> 实现了JSP页面代码的复用 <2> 使得可读性更强 导入 <%@ taglib uri="http://java.sun.com/jsp/js ...
- iOS | 地图定位
在IOS开发中,最常见的功能之一就是地图定位功能,不单单是百度地图,高德地图等专业的地图导航软件,还有美团,咕咚等一些美食购物类和运动类也需要这样的功能,所以学会这项技能是一名IOS开发工程师必须的. ...
- iOS百度地图简单使用详解
iOS百度地图简单使用详解 百度地图 iOS SDK是一套基于iOS 5.0及以上版本设备的应用程序接口,不仅提供展示地图的基本接口,还提供POI检索.路径规划.地图标注.离线地图.定位.周边雷达等丰 ...
- JavaScript-语法专题
一.数据类型的转换 概述 JavaScript是一种动态语言,变量没有类型限制,可以随时赋予任意值 强制转换:主要是值Number(),String(),Boolean三个函数 Number函数,可以 ...