標籤:put 注意 rgs 關鍵字 程式 轉化 red 區別 lib
1.Java程式設計基本概念
1.1 JVM
ClassLoader(類載入器):每一個java檔案都對應一個java類,根據程式需要逐漸載入記憶體。(一般ExtClassLoader載入java的擴充API即/lib/ext中的類,APPClassLoader用來載入使用者機器上的CLASSPATH設定的目錄中的class)。
ClassLoader載入流程:當程式運行時,JVM啟動,運行 bootstrap classloader(啟動類載入器),該ClassLoader載入Java核心API(Extclassloader和AppClassLoader也在此時被載入),調用Extclassloader載入擴充API,最後Appclassloader載入CLASSPATH目錄下定義的class。----一個程式最基本載入流程
JVM內部,統一使用編碼是Unicode表示,編碼轉換隻能發生在邊界地方,JVM和OS的交界處,也就各種輸入輸出(或者Reader,Writer類)起作用的地方。(所以面向位元組和面向字元有差別)
1.2 i++
i++是程式完畢後自增,++i是程式開始前自增
i=0;i=i++ + ++i=0+2=2
1.3 類型轉換
布爾型 數值型 字元型
低級轉進階自動轉化(如果是char類型轉進階類型,自動轉對應ASCII碼)
強制類型轉化:(類型)變數名
封裝類過度類型轉化
字串與其他類型轉化(toString()轉字串)
1.4 程式結構
assert(運算式) 斷言
1.5 運算子
& &&(和前面一個&區別是只要前面false後面無需判斷)
1.6 異常
java程式運行時出現的非正常現象,這種情況稱之為運行錯誤。 Error(由java虛擬機器產生並拋出5)和Exception
final(變數值不變或者對象引用不變)、finall、finalize(最多運行一次)
1.7 反射----是指程式可以訪問、檢測和修改它本身的狀態或行為的一種能力。
反射允許在編寫與執行時,使程式碼能夠接入裝載到JVM中的類的內部資訊,而不是原始碼中選中的的類協作代碼。需要注意的是如果使用不當,反射的成本會很高。
java中的類反射Relectiion是java程式語言開發的特點之一,它允許運行中的java程式對自身進行檢查,並能直接操作程式的內部屬性。
2 Java記憶體管理
2.1垃圾收集
顯示的分配記憶體和釋放記憶體常常引起“記憶體流失”,因此,java在建立對象時會自動分配記憶體,並在該對象引用不存在自動釋放記憶體。
垃圾收集器技術監視java程式運行。java使用一系列軟指標來跟蹤對象的各個引用,並用一個對象表將這些軟指標映射為對象的引用。使用軟指標,Java的垃圾收集器能夠以單獨的線程在後台運行,並依次檢查每個對象。(標記對象、移除對象、移動對象或檢查對象)
java語言中,判斷一塊記憶體空間是否符合垃圾收集器手機標準只有兩個條件:(1)給對象賦予了null空值以後再也沒有調用過;(2)給對象賦了新值,即重新分配了記憶體空間。
(提醒:一塊記憶體空間符合垃圾收集器的收集標準,並不意味著這塊記憶體空間就一定被記憶體回收行程回收。)
記憶體回收注意幾點:
1)不要試圖假定記憶體回收時間,未知的。
2)Java中提供一些和記憶體回收打交道的方法,而且還提供強制執行記憶體回收的方法--調用System.gc(),但是該芳芳同樣是不確定的方法。(並不能保證調用就一定能啟動來及回收,只是向JVM發出請求,一切未知)
3)挑選合適的垃圾收集器。(一般使用JVM預設選項,但,,)
4)記憶體流失問題(記憶體對象明明已經不需要的時候,還仍然保留著這塊記憶體和它的訪問方式(引用),對象都是有生命週期的,有的長,有的短,如果長生命週期的對象持有短生命週期的引用,就很可能會出現記憶體泄露)。良好的編程習慣和嚴謹的變成態度。
在Java程式中,我們通常使用new為對象分配記憶體,而這些記憶體空間都在堆(Heap)上。
此處借用別人的例子:
public class Simple { Object object; public void method1(){ object = new Object(); //...其他代碼 } }
method1方法調用結束後object對象沒有被釋放,一直到Simple結束才被釋放。
解決方案:
public class Simple { Object object; public void method1(){ object = new Object(); //...其他代碼 object=null //增加一步 } }
5)儘早釋放無用對象的引用。對於頻繁申請記憶體和釋放記憶體的操作,最好使用finalize強制執行或者自己寫finalize方法,System.gc()方法不一定適用。在jvm垃圾收集器收集一個對象之前,一般要求程式員調用適當的方法釋放資源,但在沒有明確釋放資源的情況下,java提供了預設機制終止化該對象來釋放資源,即finalize()方法。
2.2 記憶體管理
java的記憶體管理就是對象的分配和釋放問題。java中,程式員通過關鍵字new為每個對象申請記憶體(基本類型除外),所有對象都在堆中分配空間。對象釋放由gc決定和執行。gc監控每一個對象的運行狀態(申請、引用、被引用、賦值等)
記憶體泄露兩個特點:1)對象可達,即存在通路與其相連2)對象是無用的。(記憶體泄露原因:1.全域集合。2.緩衝3.ClassLoader)
2.3 clone
3.傳遞與引用
3.1傳值和傳引用
在java中,變數分為兩類。(java傳值傳引用的討論)
1)對於基礎資料型別 (Elementary Data Type)(int float long double boolean char byte),傳值的副本。
2)對於一切對象型變數,java都是傳引用的副本。傳引用副本的實質就是複製指向地址的指標。(這點與C++不同,在c++中當參數是參考型別時,傳遞的是真實的引用而不是副本)
String類型也是物件類型,所以它必然是傳引用副本。它是非可變類,使用傳值或者傳引用 顯得 沒有區別。
對於基本類型而言,傳值就是把自己複製一份傳遞,即使自己的副本變了自己也不會變。
對於物件類型,它傳的是副本引用,指向自己的地址而不是實際值的副本。因為物件類型放在堆裡,一方面速度相對於基本類型較慢,另一方面物件類型本身比較大,如果選擇重新複製值浪費記憶體且速度慢。(有趣比喻:複製鑰匙而不是複製倉庫) ---說明,一些書籍如thinking in java提到“不管是基本類型還是物件類型,都是傳值”他們是把引用副本也當做一種值。
引用傳遞例子1:
1 public class Test { 2 public static void main(String[] args) { 3 StringBuffer str= new StringBuffer("Hello"); 4 test(str); 5 System.out.println(str); 6 } 7 public static void test(StringBuffer s){ 8 s=s.append(",World!"); 9 }10 }
輸出:Hello,World!
又一個例子2:
1 public class Test { 2 public static void main(String[] args) { 3 String str= "Hello"; 4 test(str); 5 System.out.println(str); 6 } 7 public static void test(String s){ 8 s="World!"; //系統自動產生一個新的String對象設為“World”,然後把這個對象的引用賦給str. 9 }10 }
輸出:Hello
Stringl類是final類型的,因此不可以修改和繼承這個類,當例子2中函數結束,s作用消失。
例子1中StringBuffer是產生一塊記憶體空間,相關的增刪改操作都在其中,仍然是在同一段記憶體位址上進行。
String StringBuffer Stringbuilder
1)可變、不可變
String類中使用字元數組儲存字串,因為有“final”修飾符,所以可以知道string對象是不可變的。StringBuffer和Stringbuilder是可變的)
----String -----private final char value[];
-----StringBuffer和Stringbuilder -----char[] value;
2)是否安全執行緒
String中的對象是不可變的,也就可以理解為常量,顯然安全執行緒。
AbstractStringBuilder是StringBuilder與StringBuffer的公用父類,定義了一些字串的基本操作,如expandCapacity、append、insert、indexOf等公用方法。
StringBuffer對方法加了同步鎖或者對調用的方法加了同步鎖,所以是安全執行緒的。
StringBuilder並沒有對方法進行加同步鎖,所以是非安全執行緒的。
如果程式不是多線程的,那麼使用StringBuilder效率高於StringBuffer。
同理,數組傳值的本質也是傳地址值的副本。
3.2. 靜態變數與私人變數
定義在類裡的變數會預設一個初始值。布爾類型預設初始值是false
main函數不能訪問一個非靜態變數或方法
3.3.輸入/輸出流
大檔案讀取:new BufferedReader(new InputStreamReader(new FileInputStream("filename")))
寫入檔案:FileOutputStream =new FileOutStream("filename") ;out.write("string to write".getBytes());out.close();
java IO操作有面向位元組Byte和面向字元Character兩種方式.
面向位元組的操作以8位二進位為單位對資料操作,不需要對資料轉化,這些操作的類都是InputStream和ouputStream的子類。
面向字元的操作以字元為單位讀取時需要將二進位轉化為字元,寫的時候需要將字元轉化為二進位,這些類都是Reader和Writer的子類。
3.4 序列化
JAVA程式設計<5>