細說C++與Java中的引用

我們在寫java程序時,經常搞不清楚java中的引用,甚至會弄不清楚java中的引用與C++中的引用的區別,導致寫程序時容易犯錯,本小節我們會詳細講解C++與Java中的引用之異同,並弄清楚他們的本質。

1.C++的引用:

對於C++的引用,我們應弄清楚下面幾個知識:

1)聲明一個引用時,必須同時對其初始化
eg:
int main()

{
    int a = 100;
    int &r;
    cout << a <<end;
    return 0;
}
編譯上述代碼會產生如下錯誤:

錯誤的意思是r已經聲明成了引用,但是未初始化,所以我們在定義一個引用的同時要對其進行初始化,這是很重要的。

2)引用本身不佔據內存。聲明一個引用時,他只表示給一個對象定義了一個別名,其實表示的還是該對象本身,比如說,有一個人身份證上的名字是“李明”,但是在生活中還有個綽號,叫“小李”,其實這個綽號就相當於別名,“李明”和“小李”雖然叫法不同,但是確表示的是同一個人,所以對別名的操作就是對該對象本身的操作。
eg:
int main()

{
    int a = 500;
    int &r = a;        //r就是a,只是名字不同而已
    r = 600;
    cout << a << endl;
    return 0;
}
編譯後運行的結果如下:

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中的引用

在java中有兩種類型:基本類型和引用類型
其中基本類型又包含如下八種:
1、整數:包括int,short,byte,long
2、浮點型:float,double
3、字符:char
4、布爾:boolean
基本類型之外的都是引用類型
那麼基本類型與引用類型又有什麼區別呢?
最直觀的不同就是內存的表現形式不同,
對於基本類型來說,在內存中只有一塊內存區域。
如:int a = 5;此時在內存中只分配一塊內存區域,該區域名爲a,裏面的值是5,如下圖所示:


對於引用類型來說,在內存中有兩塊內存區域。

如:String str = new String("hello"); str是String類型的一個對象,存在於棧空間中,而'='後面的是new出來的一個對象,存在於堆空間中。此時在內存中就有兩塊內存區域,一塊位於棧空間中,用來存儲str,另一塊位於堆空間中,用來存儲字符串"hello"。,如下圖所示:


Java中的引用的本質:
那麼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” 的地址,但是對實參絲毫沒影響。


好了,就講到這裏咯。如果大家有什麼不懂的地方,可以多看幾遍^_^,或者在下面留言評論,我看到一般都會回覆的。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章