1. 棧(stack)與堆(heap)都是Java用來在Ram中存放數(shù)據(jù)的地方。與C++不同,Java自動管理棧和堆,程序員不能直接地設(shè)置?;蚨?。
//棧都是由運行環(huán)境來處理的,這點C++和java沒有什么不同.對于堆,不過java多了個GC. 2.這里的堆和棧首先要明確是虛擬機棧,和寄存器根本不是一個級別的東西,就別比較了. 3.棧數(shù)據(jù)共享好像是作者自己創(chuàng)造的概念.而且給基本類型也引入了"引用"的概念,不知道出于何種打算. java虛擬機規(guī)范中說:Primitive values do not share state with other primitive values. A variable whose type is a primitive type always holds a primitive value of that type. 看一下實際的處理情況: int a=3; int b=3; int c=65535; int d=65535; int e=32330; int f=32330; 看對應(yīng)的虛擬機指令,可以知道變量里實際存儲的是什么: Code: 0: iconst_3 //3 1: istore_1 2: iconst_3 //3 3: istore_2 4: ldc #2; //int 65535 6: istore_3 7: ldc #2; //int 65535 9: istore 4 11: sipush 32330 14: istore 5 16: sipush 32330 19: istore 6 21: return 可以看出每個變量保存自己的值.(具體指令的意義參考java虛擬機規(guī)范) 這里要注意的是對于int值,如果它大于short能表示的范圍,則放到常量池中去. 11: sipush 32330 14: istore 5 這句,11-13,正好是3個字節(jié)的指令大小,一個字節(jié)是sipush指令,2個字節(jié)用來存儲32330這個數(shù).兩次使用到這個數(shù),都是把它直接存給變量的,所以原貼中一直強調(diào)的"棧中共享" 的說法明顯不對. 對于65535,它是大于兩個字節(jié)的,編譯的時候把它放入常量池部分,而把取這個數(shù)的指令寫為ldc#2,我感覺這樣一個直觀的好處是減少了指令代碼的長度.尤其是多次使用到一個相同的數(shù)時. 其實,java 對變量的處理很簡單,基本類型變量存放值,引用類型存放一個"引用" (實際就是一個"指針" ,以前曾經(jīng)和別人討論過,很多人認為是個"句柄",并舉了很多證據(jù),但是我后來看到了sun的java hotspot白皮書,里面直接說明了,引用實際就是一個c的"指針" ,使用句柄需要多次間接查找,會帶來效率的瓶頸,當然這個指針并不是直接指向?qū)嶋H的對象,實際指向的是一個兩個機器字大小的對象頭,對于數(shù)組是3個機器字大小的對象頭,因為還要保存數(shù)組的長度) . java設(shè)計時保留基本類型而不把一切都設(shè)計為對象,就是出于效率考慮,如果對于基本類型再通過"引用"去查找值,何苦呢? 4.String也是包裝類? 這應(yīng)該也是作者自己定義了包裝類的概念,去java語言規(guī)范里看看什么是wrapper class. 5.Integer i = 3;編譯器如何處理? sun的編譯器是這樣處理的: Integer i=Integer.valueOf(3); 而不是通過new來創(chuàng)建了,因為Integer類中靜態(tài)的創(chuàng)建了-128~+127之間的對象,需要的數(shù)在這個范圍之內(nèi)時,直接返回,此范圍之外的數(shù)才通過new來創(chuàng)建. 簡單測試. Integer i=3; Integer j=3; 我們測試i==j會發(fā)現(xiàn)它是true. String str = new String("abc");去看String類的構(gòu)造方法會發(fā)現(xiàn),這里用的是String(String original)來創(chuàng)建的,也就是說用一個String來創(chuàng)建一個String,"abc"編譯的時候編譯器會把它加入常量池部分.不知道原貼所謂的包裝類是如何得來的. csdn 的java版有個“推薦”的專門講String常量池的帖子,很不錯。 5."JVM發(fā)現(xiàn)在棧中沒有存放該值的地址,便開辟了這個地址,并創(chuàng)建了一個新的對象,其字符串的值指向這個地址。 "又沒有分清編譯器和虛擬機的職責分配.編譯器會把"abc"放入常量池,并記住它在常量池中的位置,別的地方用到的時候編譯器直接生成ldc指令來制定了,不會讓jvm去找,去開辟地址等等. 7.原貼明顯不知道常量池的存在,好像是把常量池的數(shù)據(jù)都認為是"棧"的了. java新增了StringBuilder來處理可變字符串,如果不需要多線程環(huán)境,應(yīng)該首先選擇這個,而不是StringBuffer |
|