JAVA中可以說沒有指針,因為實際上我們在程序中不會直接操作地址,C++中的*、->操作在JAVA中都不能正常使用。
JAVA中也可以說到處都是指針,因為實際上我們定義一個對象,並給它初始化的時候,這個定義的類對象實際上就是指針。
JVAA中函數的參數是基本類型和對象類型時,他們的處理是不一樣的,基本類型傳遞的是值,而對象類型傳遞的是引用(類似於指針)。
在java中說“指針”,實際上就是說的引用。
1、指針簡單化:
其實,java中並不是沒有指針,而且指針到處都是,其實,java中對指針進行了偽裝:使用上泛化、強化和簡單化,概念上淡化和弱化。
舉個例子來說:有個Person類,我們來創建個對象:Person x = new Person();。這里就含有一個變量x,沒錯,這個引用型變量,實質上就是指針。
2、區別:
在c++中是這么創建對象指針類型的:Person *x = new Person();,x就是個指針變量;而在java中是沒有這個“* ” 的,從一定意義上說,java舍棄了指針,就不會對變量本身修改了(java中修改的是對象的值,而不是這個變量),所以也就是隨之舍棄了這個“ * ”。因此所有這些引用型變量,其實都是在使用指針,你不用這個引用型變量(指針)都不行,這就是對指針泛化和強化了。在java中不叫指針了,那么就是在概念上的淡化和弱化了。我看過一種說法,就是說創建了對象變量,稱為對象指針變量,就是這個意思。其實在java中一切對引用的操作,實質上是對數據的操作,是修改的地址、內存數據等等。
java舍棄了指針的運算操作,就是對指針的一種簡單化。
二、java中指針的應用:
可能這么說,有些牽強,但是確實可以看到指針的影子。所以只是想不到好的標題罷了。可以自己感悟一下,在java中最常見的操作:賦值;以及java的類中最熟悉的關系:繼承。都可以看到指針的影子。下面我說說我的淺顯理解,不一定是正確的,希望大家多多指正批評,在此謝過。
我先強調一下關於“指針變量”的幾點:
第一:指針變量是在棧內存中,它也是有值的,這個值存儲的就是地址單元,這個地址就是來自於賦值操作。
第二:指針變量有類型,這個類型(如Person)的含義是指針指向的變量在棧內存(不是很確定)中的范圍(大小),我理解為是占用的堆內存空間。
第三:聲明一個對象時,是對“指針變量”的定義。
第四:用new關鍵字在堆內存創建了對象,在賦值時,是把這個對象的首地址傳給了這個“指針變量”(即引用型變量)。
一)、值傳遞和引用傳遞
先看下面一段代碼:
- <span style="font-size:14px;">class A
- {
- String str;
- }
- class B
- {
- static void change(int x,A a)
- {
- x = 20;
- a.str = "h";
- }
- public static void main(String [] args)
- {
- A n = new A();
- n.str = "q";
- int x = 10;
- System.out.println("對象的引用改變前:" + n.str + " ,int型引用改變前" + x);
- change(x,n);
- System.out.println("對象的引用改變后:" + n.str + " ,int型引用改變后" + x);
- }
- }</span>
打印的結果為:
對象的引用改變前:q ,int型引用改變前:10
對象的引用改變后:h ,int型引用改變前:10
為什么會出現這種結果呢?由於Java對對象和基本的數據類型的處理是不一樣的。和c語言一樣,當把Java的基本數據類型(如int,char,double等)作為入口參數傳給函數體的時候,傳入的參數在函數體內部變成了局部變量,這個局部變量是輸入參數的一個拷貝,所有的函數體內部的操作都是針對這個拷貝的操作,函數執行結束后,這個局部變量也就完成了它的使命,它影響不到作為輸入參數的變量。這種方式的參數傳遞被稱為"值傳遞"。而在Java中用對象的作為入口參數的傳遞則缺省為"引用傳遞",也就是說僅僅傳遞了對象的一個"引用",這個"引用"的概念同C語言中的指針引用是一樣的。當函數體內部對輸入變量改變時,實質上就是在對這個對象的直接操作。圖示如下:
可以看出,在棧內存中的操作結束后,x的值是不會改變的;而對對內存中進行的操作,就會改變,因為地址沒變,所以引用是隨着地址的改變而改變的,而不是隨着值的改變而改變。