我們在寫java程序時,經常搞不清楚java中的引用,甚至會弄不清楚java中的引用與C++中的引用的區別,導致寫程序時容易犯錯,本小節我們會詳細講解C++與Java中的引用之異同,並弄清楚他們的本質。
1.C++的引用:
對於C++的引用,我們應弄清楚下面幾個知識:
1)聲明一個引用時,必須同時對其初始化
eg:
int main()
編譯上述代碼會產生如下錯誤:
錯誤的意思是r已經聲明成了引用,但是未初始化,所以我們在定義一個引用的同時要對其進行初始化,這是很重要的。
2)引用本身不佔據內存。聲明一個引用時,他只表示給一個對象定義了一個別名,其實表示的還是該對象本身,比如說,有一個人身份證上的名字是“李明”,但是在生活中還有個綽號,叫“小李”,其實這個綽號就相當於別名,“李明”和“小李”雖然叫法不同,但是確表示的是同一個人,所以對別名的操作就是對該對象本身的操作。
eg:
int main()
編譯後運行的結果如下:
3)不能對數組求引用
4)引用作爲參數
首先來看下面的代碼:
#include <iostream>
using namespace std;
void f(int &r) //r是a的別名,r與a表示的是同一個對象,對r的操作就是對a的操作
{
cout << "r:" << r << endl;
cout << "&r:" << &r << endl;
r = 600;
cout << "r:" << r << endl;
cout << "&r:" << &r << endl;
}
int main()
{
int a = 500;
cout << "a:" << a << endl;
cout << "&a:" << &a << endl;
f(a);
cout << "a:" << a << endl;
cout << "&a:" << &a << endl;
return 0;
}
我們可以看到,形參是一個引用。第2)點已經提到了,引用只是某一個對象的別名,其實代表的還是該對象本身,所以可以說,r就是a。
編譯後的結果如下:
從運行結果來看,我們起碼可以看到兩點重要的信息,第1點是通過對r的修改確實也改變了a的值,第2點是r的地址與a的地址是一樣的,從而驗證了“r就是a”,只是名字不同而已,其實都表示同一個對象。
小結:C++中的引用其實就是一個對象的別名,對引用的操作其實也就是對該對象的操作,並且聲明引用的時候一定要對其初始化。
2.Java中的引用
2、浮點型:float,double
3、字符:char
4、布爾:boolean
基本類型之外的都是引用類型。
那麼基本類型與引用類型又有什麼區別呢?
最直觀的不同就是內存的表現形式不同,
對於基本類型來說,在內存中只有一塊內存區域。
如:int a = 5;此時在內存中只分配一塊內存區域,該區域名爲a,裏面的值是5,如下圖所示:
對於引用類型來說,在內存中有兩塊內存區域。
那麼Java中的引用到底是什麼呢?是否類似於C++中的引用呢?我們舉個例子來看一下:
java代碼:
public class Person {
private String name;
public static void main(String[] args) {
Person p1 = new Person("zhang san");
Person p2 = new Person("li si");
Person p = p1;
p1 = p2;
System.out.println("p.name: " + p.getName());
System.out.println("p1.name: " + p1.getName());
System.out.println("p2.name: " + p2.getName());
}
public Person(String name){
this.name = name;
}
public String getName() {
return name;
}
}
第6行執行完後如下圖所示:
第7行執行完後如下圖所示:
第9行執行完後如下圖所示:
第10行執行完後如下圖所示:
所以最終打印的結果如下圖所示:
其對應的C++代碼如下:
#include <iostream>
using namespace std;
class person
{
public:
person(string name)
{
this->name = name;
}
string getName()
{
return name;
}
private:
string name;
};
int main()
{
person *p1 = new person("zhang san");
person *p2 = new person("li si");
person *p = p1;
p1 = p2;
cout << "p->name: " << p->getName() << endl;
cout << "p1->name: " << p1->getName() << endl;
cout << "p2->name: " << p2->getName() << endl;
return 0;
}
我們可以看出,Java中的引用相當於C++中的指針,而不是C++中的引用。
本質弄清楚了,java中的引用也就相當於C++中的指針,我們知道指針相當於地址,所以我們也可以這樣理解,java中的引用相當於對象的地址。
我們回過頭再來解讀一下Person p1 = new Person("zhang san");後面的new Person("zhang san")會new出來一個對象,而該對象的地址就保存在p1中。
3.Java傳遞參數
我們都知道,java有兩種數據類型:基本類型和引用類型。那麼自然而然的,傳遞參數也要分爲這兩種情況加以討論。
1)參數是基本類型
傳遞基本類型是按值傳遞的,即在函數內部該形參只是實參的一個拷貝,在函數內對形參的操作對實參不會有任何影響,這個就不多說了。
2)參數是引用類型
對於這種情況,稍微難以理解一點,不過只要把我上面講的都弄透了,其實這種情況也好理解,下面先來看一個例子:
public class Person {
private String name;
public static void main(String[] args) {
Person p1 = new Person("zhang san");
test(p1.name);
System.out.println(p1.name);
}
public Person(String name){
this.name = name;
}
public String getName() {
return name;
}
public static void test(String str){
str = "wang wu";
}
}
我們把test方法聲明爲static方法,是要將這個方法聲明爲類的方法,而不屬於某個對象。我們看他的運行結果如下圖所示:
很多人可能對這個結果感到很困惑,其實沒什麼好睏惑的。這裏的形參str也是對實參的一個拷貝,只不過這個拷貝稍微不同於一般的值拷貝。因爲參數是String類型的,不是基本類型,是一個引用類型,所以它裏面保存的是一個指針,或者說是一個地址,這個指針所指向的那一塊內存區域裏面存放的纔是真正的值。剛纔說了,這個形參str只是對形參p1.name的一個拷貝而已,也就是將p1.name裏存放的地址賦值給了str,也就是說,str裏存放的數據等於p1.name裏存放的數據,而這個數據是一個地址值。
在test函數體內,str = "wang wu";這一句其實我們只是修改了str裏存放的數據,將str裏存放的數據改成了字符串“wang wu” 的地址,但是對實參絲毫沒影響。
好了,就講到這裏咯。如果大家有什麼不懂的地方,可以多看幾遍^_^,或者在下面留言評論,我看到一般都會回覆的。