碰到一道面试题,查了好多资料才把这个问题弄明白,在此做个记录,纯属个人理解,仅供参考,如有问题,欢迎指正。
先把题目贴出来:
public class Test {
public static void main(String[] args){
int i=1;
change(i);
System.out.println(i);
}
static void change(int i){
i+=1;
}
}
what is the result?
A:0 B:1 C:2 D:Compile time error
答案是B,而非C。类似的题目还有如下:
public class Base {
private String name;
private String sex;
public Base(String x,String y){
this.name=x;
this.sex=y;
}
public String toString(){
return name+","+sex;
}
//更改对象属性
public static void Update(Base b){
b.name="name3";
b.sex="f";
}
//交换对象引用
public static void Swap(Base b1,Base b2){
Base temp=b1;
b1=b2;
b2=temp;
System.out.println("In The Swaping:b1<"+b1+">\tb2<"+b2+">"); //交换方法中输出交换效果
}
public static void main(String[] args){
Base b1=new Base("name1","m");
Base b2=new Base("name2","f");
System.out.println("Before Swaping:b1<"+b1+">\tb2<"+b2+">"); //调用交换方法前效果
Swap(b1,b2); //调用交换方法
System.out.println("After Swaping:b1<"+b1+">\tb2<"+b2+">"); //调用交换方法后效果
Update(b1);
System.out.println("After Update:b1<"+b1+">\tb2<"+b2+">"); //调用交换方法后效果
}
}/*output
Before Swaping:b1<name1,m> b2<name2,f>
In The Swaping:b1<name2,f> b2<name1,m> //在方法中交换成功
After Swaping:b1<name1,m> b2<name2,f> //执行交换方法后却没有实现交换?
After Update:b1<name3,f> b2<name2,f> //交换没有成功,更改操作却成功了,Why?
*/
Java中的变量分基本类型和引用类型。基本类型即boolean、char、int、short、long、double、string等八种类型,此外的为引用类型。C++中的函数参数传递有值传递、引用传递和地址传递。引用是指向对象的内存地址。值传递是指在调用函数时将实际参数复制一份传递到函数中,这样在函数中如果对参数进行修改,将不会影响到实际参数,如(来自百度百科)。
#include<iostream.h>
void fun(int a)
{
a=10; //修改参数
}
int main()
{
int a=20;
fun(a); //调用fun函数
cout<<a<<endl; //输出变量,变量的值没改变
return 0;
}
引用传递是指在调用函数时将实际参数的地址传递到函数中,那么在函数中对参数所进行的修改,将影响到实际参数。
void swap(int *a, int *b)
{
int t = *b;
*b = *a;
*a = t;
cout <<"In Swap:"<< *a <<","<< *b<<endl; //交换函数中
}
int _tmain(int argc, _TCHAR* argv[])
{
int i = 5;
int j = 9;
cout << "Before Swap:" << i << "," << j<< endl;//交换前
swap(&i,&j);
cout <<"After Swap:"<< i <<","<< j<<endl; //执行交换函数后
system("pause");
}/*output:
Before Swap:5,9
In Swap:9,5
After Swap:9,5 //实际值已发生更改
*/
在C++中可以通过指针来完成引用传递和地址传递,但在Java中是没有指针的,因此在Java方法参数传递中只有值的传递。对象作为方法参数时,传递的对象的引用,但并非是C++中的引用传递,而是传递的是“引用”的值,所以本质上还是值传递。将上面程序修改如下:
void swap(int *a, int *b)
{
int *t = b;
b = a;
a = t;
cout <<"In Swap:"<< *a <<","<< *b<<endl; //交换函数中
}
int _tmain(int argc, _TCHAR* argv[])
{
int i = 5;
int j = 9;
cout << "Before Swap:" << i << "," << j<< endl;//交换前
swap(&i,&j);
cout <<"After Swap:"<< i <<","<< j<<endl; //执行交换函数后
system("pause");
}/*output:
Before Swap:5,9
In Swap:9,5
After Swap:5,9 //实际值没有发生更改
*/
此函数实现的本质与前两题JAVA考题是一样的,方法中发生交换的是封装在Java中的C++指针,而对于实际对象没有影响。根据值传递的概念,当一个对象实例作为一个参数被传递到方法中时,参数值为该对象的“引用”一个副本。所以,在交换方法中成功交换的均是该对象引用的副本,如图:
由于引用值更换不变,故在方法中输出效果为正常交换,而此并未改变原引用,所以最后对象的值还是不变。但是方法中作为副本的引用同样指向实际对象,故而对象属性可以在被调用的方法中改变,但对象的原引用是不会改变的。