1. 程式人生 > >JAVA程序設計<5>

JAVA程序設計<5>

都在 jvm 對象類型 ppc close 內存 開發 buffer tcl

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)對於基本數據類型(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>