java中方法参数分为两种类型
- 基本数据类型(整数,浮点,布尔,字符)
- 对象引用
基本数据类型
声明一个整型变量和一个浮点型变量a和b,并且给它们赋值。
int a = 10;
double = 20.0;
对于基本数据类型,会在栈内存中开辟一个空间,变量中存储的是真实的数据,如下图所示
java总是采用按值调用,也就是说方法得到的是所有参数值的一个拷贝,方法不能修改传递给它的任何参数变量的内容。例如,考虑下面的调用:
public static void tripleValue(double x)
{
x = 3 * x;
}
double percent = 10.0;
tripleValue(percent);
调用tripleValue方法是不能改变percent的值的。原因如下:
执行double percent = 10.0
,会在栈内存中创建一个10并且存储在变量percent当中,把percent传递给方法tripleValue的时候,会再复制一个10,并且存储在变量x当中,所以修改x的值并不影响percent的值。
对象引用
当一个变量的值不是基本数据类型的时候,变量存储的就不是真实的值了,而是存储真实值对应的地址值。例如
Student s = new Student();
new Student()
会在堆中创建这个对象,真实值是存储在堆空间中。而s存储的是这个对象在堆空间中的地址,即s指向这个对象。如下图所示
所以说s不是基本数据类型,它是对象引用。把对象引用作为方法的参数和把基本数据类型作为方法的参数是不同的,虽然两者都是按值调用。例如:
public static void changeScore(Student x) //这个函数的作用是
//更改这名同学的英语分数
{
x.englishScore = 85.0;
}
Student s = new Student();
changeScore(s);
如果同学s的英语分数原本为90分,那么通过changeScore函数的作用后,同学s的英语分数会变为85分。为什么分数会变?为什么基本数据类型执行类似的操作无法更改实参的值呢?原因在于对象引用存储的是地址值,而不是真实的变量值。
当执行changeScore(s)的时候,会复制一份s的拷贝,这个拷贝的值也是地址值,把这个拷贝的值传给了对象引用x,所以x存储的地址值和s存储的地址值是一样的。那么对象引用x和对象引用s都是指向堆内存中同一个真实值。既然大家都是指向堆内存中同一个真实值,那么执行x.englishScore = 85.0;
的时候就是修改这个真实值,所以同学s的分数就会发生改变。
引用调用
那么当方法参数是对象引用的时候,程序执行的是引用调用吗?不是的,自始至终,无论是方法参数是基本数据类型还是对象引用,程序执行的都是值调用,也即是拷贝了一份值,只不过基本数据类型拷贝的是变量的真实值,而对象引用拷贝的是地址值。那么什么是引用调用?引用调用表示方法接收的是调用者提供的变量地址。在C++中:
void swap(int &x, int &y)
{
int temp;
temp = x;
x = y;
y = temp;
}
void main()
{
int a = 5;
int b = 9;
swap(a, b);
}
当执行swap(a, b);
的时候,由于形参是引用,所以这里执行的是引用调用。也即是说x是a的别名,修改a的值就是修改x的值。注意和值调用不同的是,引用调用并没有拷贝出一个新的相同的地址值,而是把x作为a的别名。也就是说,如果你把x指向另外一个变量值,那么a也会指向那个变量值,因为你操作x就是在操作a。
但对于java中的对象引用来说,例如
public static void change(Student c)
{
c = new Student();
}
Student s = new Student();
change(s);
分析一下,由于对象引用采取的是值调用,所以当执行change(s);
的时候会拷贝一个新的地址值,对象引用c和对象引用s存储的地址值是相同,所以它们都指向同一个真实值。但当执行c = new Student();
的时候,对象引用c会指向一个新的真实值,也就是说存储的地址值改变了。那么对象引用s存储的地址值有改变吗?注意!对象引用s存储的还是原来那个地址值,指向的还是原来那个真实值。