一般谈到函数的参数传递的时候都会想到值传递和引用传递。看看本文的例子就会很清楚了。
public class MethodParameter {
public static void main(String[] args) {
String str = "Hello";
char[] c = new char[] { 'W', 'o', 'r', 'l', 'd' };
StringBuffer sb = new StringBuffer("Jacky");
changeAddr(str, c, sb);
System.out.println(str);
System.out.println(c);
System.out.println(sb.toString());
changeValue(str, c, sb);
System.out.println(str);
System.out.println(c);
System.out.println(sb.toString());
}
private static void changeAddr(String str, char[] c, StringBuffer sb) {
str = "Hi";
c = new char[] { 'C', 'h', 'i', 'n', 'a' };
sb = new StringBuffer(" Cheng");
}
private static void changeValue(String str, char[] c, StringBuffer sb) {
str.toUpperCase();
c[0] = 'C';
sb.append(" Cheng");
}
}
你认为会得到什么结果呢?不如先别看结果看看你是不是能做对。
引用
Hello
World
Jacky
Hello
Corld
Jacky Cheng
因为值传递很简单,比如传int值,你肯定知道在函数里无论你怎么修改这个int值都不会改变它传进来之前的变量的值。所以,我的这个例子中都是引用传递。
我觉得得说明一下什么是值,什么时候引用。其实值通常是只原始数据类型比如int,char等,但不包括String哦。所谓引用就是只指向对象或者数组的地址的值。
知道了这个,就应该知道上面sb的变化原因了。至于str,你可知道String是immutable类,所以你是没有办法修改它的值的,只能改变它的引用。对于c,是一个数组,数组引用和对象引用遵循同样的规制。
另外其实数组也是一种对象,而且还是一级对象,还记的你对数组的构建也是new出来的吗?无论是原始值数组还是对象数组基本没有什么区别,只是前者存原始类型的值,后者存贮对象的引用值。数组只有一个只读成员length,它告诉你数组的长度。另外还有唯一一个访问方法就是'[]',通过这个你可以读取或者赋值某一个数组元素。如果你用过java.lang.System提供的数组copy方法:
public static void arraycopy(Object src,
int srcPos,
Object dest,
int destPos,
int length)
int[] dataFrom = new int[]{1,2,3};
int[] dataTo = new int[10];
//把dataFrom 所有元素copy到dataTo里从3开始的后面。
System.arraycopy(dataFrom , 0, dataTo, 3, 3);
你看,数组是可以作为Object传入这个方法的,利用这一点,你也可以自己写通用的数组函数了。只要把Object作为形参类型就好。
进一步的思考
可以看出Java中参数的传递是传递的值,不过这个值有两种,一种是我们看得到的值,也就是primitive类型,比如int,double,char类型的值。另一种就是我们看不到的值,也就是地址值,也可以说是引用值,就是你传递对象或数组类型的参数时传递的值。
其实我们也可以这么理解,当传参数的时候,会把参数的primitive值或者引用值copy给形式参数。因此,任你在方法里面怎么修改这些值都不会对原来的变量有影响。
但是对于引用值,如果你在方法里面利用这个引用值访问对象或者数组里面的数据或方法的时候,这和在方法外面直接做事一样的。因为他们持有的是同一个地址。
理解了这些,试想一下,如果在参数前加上final有什么好处吗?
如果是primitive的参数,有什么用?只能是说你在方法里面不能修改这个变量的值。其实你就算修改了,也只是对方法自己有影响,不会对调用者有影响。
如果是引用类型的参数呢?又有什么用?不可能说不让你修改对象的值,只能不让你修改这个形式参数变量的引用值。到底有什么好处呢?
从设计API的角度来说,如果你在primitive参数上加上final,就是告诉自己,这些值对于我的方法来说就是常量,是我需要参考的东西。他们的值在我的整个方法的所有的地方都是一样的。试想,如果不加final,有可能你在方法里面前后两次访问这个变量的值不同,因为你在这之间无意中修改了它。这样就达不到你的意图。
那么如果是引用类型的参数呢?这里面的意图,就是告诉你在方法里面访问(不论是读还是修改)的这个对象就是传进来的对象,而不是别的。同样保证你在方法里面不同地方的操作都是对这一个对象的操作。
再进一步的思考
有了前面的思考,我们就可以知道,在设计方法的时候,尽量在参数前面加上final,不管是primitive类型的还是在引用类型的前面。因为这样意图非常简单清楚,在方法里面也可以大胆的引用。回顾你需要修改它们的时候,是不是无意中把他们当成自己定义的临时变量了,这样很危险,容易出乱子。这样是为什么当你用sun的规范做check style的时候他让你改的原因。
还要再来一点思考
为什么当你调用回调函数的时候必须得加final呢?看了一篇文章说是多线程以及垃圾回收的原因迫使的,我得研究以后再来补充。
分享到:
相关推荐
java 中函数的参数传递详细介绍 java 中函数的参数传递详细介绍
Java的引用和函数参数传递Java的引用和函数参数传递Java的引用和函数参数传递Java的引用和函数参数传递
函数调用参数传递类型(java)的用法介绍..ppt
C、C++函数参数传递方式.pdf
java传递参数的方法 很的东西 大家下载学习一下
浅析Java引用类型和方法参数传递,浅析Java引用类型和方法参数传递
参数传递是Java语言中函数调用的重要步骤,清楚地了解参数传递的过程是编写出高质量程序所必须的.大多数程序设计语言具有传值调用和传引用调用的两种方法.通过对典型程序的研究与分析可以看出JAVA语言的参数传递总是...
在传统的观念里,都认为JavaScript函数...对于这里的输出20,10,按照JS的官方解释就是在基本类型参数传递的时候,做了一件复制栈帧的拷贝动作,这样外部声明的变量num和函数参数的num,拥有完全相同的值,但拥有完全不
android中js与java间函数相互调用demo,绝对开源运行,并且解决了中文作为参数传递乱码问题。
但在多线程的异步开发模式下,数据的传递和返回和同步开发模式有很大的区别。由于线程的运行和结束是不可预料的,因此,在传递和返回数据时就无法象函数一样通过函数参数和return语句来返回数据
函数调用时,参数传递的方式主要有两种: 值传递和引用传递。 Java使用的是值传递。值传递是把变量的值、常数或常量传递给参数。而引用传递,是把变量的所在内存中的地址传递给参数,参数通过地址找
前言在Java中,当对象作为参数传递时,究竟传递的是对象的值,还是对象的引用,这是一个饱受争议的话题。若传的是值,那么函数接收的只是实参本,函数对形参的操作并不
我们先看一下值传递和引用传递的概念...值传递的函数中无法改变原始对象,引用传递中函数 可以改变原始对象 我们通过例子理解一下Java的值传递: public static void main(String[] args) { int a = 10; int b = 20;
自定义函数参数传递为 字符串格式 ,传递方式 1:用this传递 2:引号缺省 3:转义字符(html中 代表”双引号,'代表单引号,javascript中直接\” 和Java通用转义字符集) <html> <head> [removed] ...
Java函数式编程是指利用函数式编程的思想和特性来开发Java应用程序。函数式编程强调将计算过程视为数学函数的求值,侧重于函数的组合、映射、过滤等操作,同时避免了可变状态和可变数据。 在Java中,函数式编程主要...
主要代码审计方法是跟踪...敏感函数参数回溯,根据敏感函数,逆向追踪参数传递的过程。这个方法是最高效,最常用 的方法。大多数漏洞的产生是因为函数的使用不当导致的,只要找到这些函数,就能够快速挖掘想要的漏洞。
NDK开发时,C/C++调用Java的函数的一些案例; 传递int类型参数: https://blog.csdn.net/niuba123456/article/details/80978500 传递String类型参数: https://blog.csdn.net/niuba123456/article/details/80978916 ...
定义一个圆类circle,它有一个变量radius(半径)。从键盘输入数据,通过构造函数的参数传递给radius,编程计算并输出圆的的周长和面积。但是,必须确保输入的数据不为复数。
相信每一位刚接触javascript的同学在函数参数传递上都会很疑惑,原因无他,那就是它的语法太怪异了,你定义一个函数 例如 function test(name,msg){ return 'hello' + name + msg; } 那么你在调用的时候怎么调呢,你...