Java语言中函数的参数传递方式基本上可以分为两类:1.基本数据类型、2.引用数据类型(对象类型)。
1. 基本数据类型有哪些?下面我们通过实际才代码测试来观察,首先是常见的int、double、char等。
public class TestPara
{
public static void changeValue(int temp)
{
temp = 10;
}
public static void changeValue(double temp)
{
temp = 0.123456;
}
public static void changeValue(char temp)
{
temp = 'b';
}
public static void main(String[] args)
{
int intValue = 1;
System.out.println("--调用函数前的值:" + intValue);
changeValue(intValue);
System.out.println("--调用函数后的值:" + intValue);
double doubleValue = 0.1;
System.out.println("--调用函数前的值:" + doubleValue);
changeValue(doubleValue);
System.out.println("--调用函数后的值:" + doubleValue);
char charValue = 'a';
System.out.println("--调用函数前的值:" + charValue);
changeValue(charValue);
System.out.println("--调用函数后的值:" + charValue);
}
}
输出结果:
--调用函数前的值:1
--调用函数后的值:1
--调用函数前的值:0.1
--调用函数后的值:0.1
--调用函数前的值:a
--调用函数后的值:a
显然,这里将int、double、char作为参数传递给changeValue函数时,只是将其值作了一次拷贝,其本身的值在函数调用前后并没有变化。
下面登场的当然是大家经常使用的String、StringBuilder、StringBuffer了。
public static void changeValue(String temp)
{
temp = "hello world!";
}
public static void changeValue(StringBuilder temp)
{
temp.append(" world!");
}
public static void changeValue(StringBuffer temp)
{
temp.append(" world!");
}
String strValue = "hello";
System.out.println("--调用函数前的值:" + strValue);
changeValue(strValue);
System.out.println("--调用函数后的值:" + strValue);
StringBuilder strbuildValue = new StringBuilder("hello");
System.out.println("--调用函数前的值:" + strbuildValue);
changeValue(strbuildValue);
System.out.println("--调用函数后的值:" + strbuildValue);
StringBuffer strbuffdValue = new StringBuffer("hello");
System.out.println("--调用函数前的值:" + strbuffdValue);
changeValue(strbuffdValue);
System.out.println("--调用函数后的值:" + strbuffdValue);
输出结果:
--调用函数前的值:hello
--调用函数后的值:hello
--调用函数前的值:hello
--调用函数后的值:hello world!
--调用函数前的值:hello
--调用函数后的值:hello world!
这里不同的地方就产生了,String和int等基本数据类型一样,传递的时候同样是将其值拷贝了一个作为形参。StringBuilder和StringBuffer的传递方式不一样,其传递的是引用(实际内存中的地址)下面以StringBuilder为例说明,当调用new StringBuilder时就会在内存堆中创建一个strbuildValue对象,当将其作为函数参数传递时,实际上是将其内存地址传到了函数内部,而函数内部对其的处理就会相应的改变此内存地址中的值,所以strbuildValue对象本身的值就会相应改变。因为Java没有指针,这里的引用类型传递就有点类似C/C++中指针的味道,然而需要注意的是:虽然引用传递能够改变原对象的值、但是其指向的内存地址是不能改变的。
那么,除了StringBuilder、StringBuffer之外还有那些类型在Java中是按照引用传递的了?它们是:所有的复合数据类型:如数组,接口、类、Json、Json数组等。既然知道了那些数据类型是值传递、那些是址传递,下面来看下一个列子。如果我需要交换两个StringBuilder对象的值,那么我是否只需要将两者作为实参传递过去交由函数处理就OK了?
public static void swapValue(StringBuilder a, StringBuilder b)
{
StringBuilder temp = b;
b = a;
a = temp;
}
StringBuilder sb_a = new StringBuilder("a"), sb_b = new StringBuilder("b");
System.out.println("--交换前: sb_a=" + sb_a + " sb_b=" + sb_b);
swapValue(sb_a, sb_b);
System.out.println("--交换后: sb_a=" + sb_a + " sb_b=" + sb_b);
输出结果:
--交换前: sb_a=a sb_b=b
--交换后: sb_a=a sb_b=b
调用swapValue()函数的时候,我们将实参sb_a和sb_b的地址传递给了形参a和b,然而函数内部的形参相互赋值的时候仅仅是将对方的内存地址交换了。也就是说,函数内部实现的功能仅仅是交换了形参的的值,而实参的值依旧没有改变,当然就达不到我们函数的要求!
所以在处理这些问题的时候,我们应该特别注意值传递与址传递的区别,尤其是在函数内部涉及到对参数修改的时候要特别注意,如果想要修改参数值最好的方式是通过返回值来处理,如果不想修改参数值最好是在函数内重新声明一个对象将原参数的值拷贝一份。