第一篇:java習慣用法總結
在Java編程中,有些知識 并不能僅通過語言規范或者標準API文檔就能學到的。在本文中,我會盡量收集一些最常用的習慣用法,特別是很難猜到的用法。(Joshua Bloch的《Effective Java》對這個話題給出了更詳盡的論述,可以從這本書里學習更多的用法。)
我把本文的所有代碼都放在公共場所里。你可以根據自己的喜好去復制和修改任意的代碼片段,不需要任何的憑證。
目錄
? 實現:
o equals()o hashCode()o compareTo()o clone()? 應用:
o StringBuilder/StringBuffer o Random.nextInt(int)o Iterator.remove()o StringBuilder.reverse()o Thread/Runnable o try-finally ? 輸入/輸出:
o 從輸入流里讀取字節數據 o 從輸入流里讀取塊數據 o 從文件里讀取文本 o 向文件里寫文本 ? 預防性檢測:
o 數值 o 對象 o 數組索引 o 數組區間 ? 數組:
o 填充元素
o 復制一個范圍內的數組元素 o 調整數組大小 ? 包裝
o 個字節包裝成一個int o 分解成4個字節
實現equals()class Person { String name;intbirthYear;byte[] raw;publicboolean equals(Object obj){ if(!objinstanceof Person)return false;Person other =(Person)obj;returnname.equals(other.name)&&birthYear == other.birthYear &&Arrays.equals(raw, other.raw);} publicinthashCode(){...} } ? ? 參數必須是Object類型,不能是外圍類。
foo.equals(null)必須返回false,不能拋NullPointerException。(注意,null instanceof 任意類 總是返回false,因此上面的代碼可以運行。)
? ? ? 基本類型域(比如,int)的比較使用 ==,基本類型數組域的比較使用Arrays.equals()。覆蓋equals()時,記得要相應地覆蓋 hashCode(),與 equals()保持一致。參考: java.lang.Object.equals(Object)。
實現hashCode()class Person { String a;Object b;byte c;int[] d;publicinthashCode(){ returna.hashCode()+ b.hashCode()+ c + Arrays.hashCode(d);} publicboolean equals(Object o){...} } ? ? 當x和y兩個對象具有x.equals(y)== true,你必須要確保x.hashCode()== y.hashCode()。根據逆反命題,如果x.hashCode()!= y.hashCode(),那么x.equals(y)== false 必定成立。? 你不需要保證,當x.equals(y)== false時,x.hashCode()!= y.hashCode()。但是,如果你可以盡可能地使它成立的話,這會提高哈希表的性能。
? hashCode()最簡單的合法實現就是簡單地return 0;雖然這個實現是正確的,但是這會導致HashMap這些數據結構運行得很慢。
? 參考:java.lang.Object.hashCode()。
實現compareTo()class Person implements Comparable
{ String firstName;String lastName;int birthdate;// Compare by firstName, break ties by lastName, finally break ties by birthdate publicintcompareTo(Person other){ if(firstName.compareTo(other.firstName)!= 0)returnfirstName.compareTo(other.firstName);else if(lastName.compareTo(other.lastName)!= 0)returnlastName.compareTo(other.lastName);else if(birthdate
? ? ? 只關心返回結果的正負號(負/零/正),它們的大小不重要。Comparator.compare()的實現與這個類似。參考:java.lang.Comparable。
實現clone()class Values implements Cloneable { String abc;double foo;int[] bars;Date hired;public Values clone(){ try { Values result =(Values)super.clone();result.bars = result.bars.clone();result.hired = result.hired.clone();return result;} catch(CloneNotSupportedException e){ // Impossible throw new AssertionError(e);} } } ? ? 使用 super.clone()讓Object類負責創建新的對象。
基本類型域都已經被正確地復制了。同樣,我們不需要去克隆String和BigInteger等不可變類型。? ? 手動對所有的非基本類型域(對象和數組)進行深度復制(deep copy)。
實現了Cloneable的類,clone()方法永遠不要拋CloneNotSupportedException。因此,需要捕獲這個異常并忽略它,或者使用不受檢異常(unchecked exception)包裝它。
? ? 不使用Object.clone()方法而是手動地實現clone()方法是可以的也是合法的。參考:java.lang.Object.clone()、java.lang.Cloneable()。
使用StringBuilder或StringBuffer // join([“a”, “b”, “c”])-> “a and b and c” String join(List
使用StringBuilder或者StringBuffer時,可以使用append()方法添加文本和使用toString()方法去獲取連接起來的整個文本。
? 優先使用StringBuilder,因為它更快。StringBuffer的所有方法都是同步的,而你通常不需要同步的方法。
? 參考java.lang.StringBuilder、java.lang.StringBuffer。
生成一個范圍內的隨機整數 Random rand = new Random();// Between 1 and 6, inclusive intdiceRoll(){ returnrand.nextInt(6)+ 1;} ? ? 總是使用Java API方法去生成一個整數范圍內的隨機數。
不要試圖去使用 Math.abs(rand.nextInt())% n 這些不確定的用法,因為它的結果是有偏差的。此外,它的結果值有可能是負數,比如當rand.nextInt()== Integer.MIN_VALUE時就會如此。
? 參考:java.util.Random.nextInt(int)。
使用Iterator.remove()void filter(List
返轉字符串
String reverse(String s){ return new StringBuilder(s).reverse().toString();} ? ? 這個方法可能應該加入Java標準庫。
參考:java.lang.StringBuilder.reverse()。
啟動一條線程
下面的三個例子使用了不同的方式完成了同樣的事情。實現Runnnable的方式:
void startAThread0(){ new Thread(new MyRunnable()).start();} classMyRunnable implements Runnable { public void run(){...} } 繼承Thread的方式:
void startAThread1(){ newMyThread().start();} classMyThread extends Thread { public void run(){...} } 匿名繼承Thread的方式:
void startAThread2(){ new Thread(){ public void run(){...} }.start();} ? 不要直接調用run()方法??偸钦{用Thread.start()方法,這個方法會創建一條新的線程并使新建的線程調用run()。
? 參考:java.lang.Thread, java.lang.Runnable。
使用try-finally I/O流例子:
voidwriteStuff()throws IOException { OutputStream out = new FileOutputStream(...);try { out.write(...);} finally { out.close();} } 鎖例子:
voiddoWithLock(Lock lock){ lock.acquire();try {...} finally { lock.release();} } ? 如果try之前的語句運行失敗并且拋出異常,那么finally語句塊就不會執行。但無論怎樣,在這個例子里不用擔心資源的釋放。
? 如果try語句塊里面的語句拋出異常,那么程序的運行就會跳到finally語句塊里執行盡可能多的語句,然后跳出這個方法(除非這個方法還有另一個外圍的finally語句塊)。
從輸入流里讀取字節數據
InputStream in =(...);try { while(true){ int b = in.read();if(b ==-1)break;(...process b...)} } finally { in.close();} ? read()方法要么返回下一次從流里讀取的字節數(0到255,包括0和255),要么在達到流的末端時返回-1。
? 參考:java.io.InputStream.read()。
從輸入流里讀取塊數據
InputStream in =(...);try { byte[] buf = new byte[100];while(true){ int n = in.read(buf);if(n ==-1)break;(...process buf with offset=0 and length=n...)} } finally { in.close();} ? ? 要記住的是,read()方法不一定會填滿整個buf,所以你必須在處理邏輯中考慮返回的長度。參考: java.io.InputStream.read(byte[])、java.io.InputStream.read(byte[], int, int)。
從文件里讀取文本
BufferedReader in = new BufferedReader(newInputStreamReader(new FileInputStream(...), “UTF-8”));try { while(true){ String line = in.readLine();if(line == null)break;(...process line...)} } finally { in.close();} ? BufferedReader對象的創建顯得很冗長。這是因為Java把字節和字符當成兩個不同的概念來看待(這與C語言不同)。
? ? ? ? ? 你可以使用任何類型的InputStream來代替FileInputStream,比如socket。當達到流的末端時,BufferedReader.readLine()會返回null。要一次讀取一個字符,使用Reader.read()方法。
你可以使用其他的字符編碼而不使用UTF-8,但最好不要這樣做。參考:java.io.BufferedReader、java.io.InputStreamReader。
向文件里寫文本
PrintWriter out = new PrintWriter(newOutputStreamWriter(new FileOutputStream(...), “UTF-8”));try { out.print(“Hello ”);out.print(42);out.println(“ world!”);} finally { out.close();} ? Printwriter對象的創建顯得很冗長。這是因為Java把字節和字符當成兩個不同的概念來看待(這與C語言不同)。
? ? ? 就像System.out,你可以使用print()和println()打印多種類型的值。你可以使用其他的字符編碼而不使用UTF-8,但最好不要這樣做。參考:java.io.PrintWriter、java.io.OutputStreamWriter。
預防性檢測(Defensive checking)數值
int factorial(int n){ if(n < 0)throw new IllegalArgumentException(“Undefined”);else if(n >= 13)throw new ArithmeticException(“Result overflow”);else if(n == 0)return 1;else return n * factorial(noff 填充數組元素 使用循環: // Fill each element of array 'a' with 123 byte[] a =(...);for(int i = 0;i Arrays.fill(a,(byte)123);? ? 參考:java.util.Arrays.fill(T[], T)。 參考:java.util.Arrays.fill(T[], int, int, T)。 復制一個范圍內的數組元素 使用循環: // Copy 8 elements from array 'a' starting at offset 3 // to array 'b' starting at offset 6, // assuming 'a' and 'b' are distinct arrays byte[] a =(...);byte[] b =(...);for(int i = 0;i < 8;i++)b[6 + i] = a[3 + i];(優先)使用標準庫的方法: System.arraycopy(a, 3, b, 6, 8);? 參考:java.lang.System.arraycopy(Object, int, Object, int, int)。 調整數組大小 使用循環(擴大規模): // Make array 'a' larger to newLen byte[] a =(...);byte[] b = new byte[newLen];for(int i = 0;i // Make array 'a' smaller to newLen byte[] a =(...);byte[] b = new byte[newLen];for(int i = 0;i a = Arrays.copyOf(a, newLen);? ? 參考:java.util.Arrays.copyOf(T[], int)。 參考:java.util.Arrays.copyOfRange(T[], int, int)。把4個字節包裝(packing)成一個int intpackBigEndian(byte[] b){ return(b[0] & 0xFF)<< 24 |(b[1] & 0xFF)<< 16 |(b[2] & 0xFF)<< 8 |(b[3] & 0xFF)<< 0;} intpackLittleEndian(byte[] b){ return(b[0] & 0xFF)<< 0 |(b[1] & 0xFF)<< 8 |(b[2] & 0xFF)<< 16 |(b[3] & 0xFF)<< 24;} 把int分解(Unpacking)成4個字節 byte[] unpackBigEndian(int x){ return new byte[] {(byte)(x>>> 24),(byte)(x>>> 16),(byte)(x>>> 8),(byte)(x>>> 0)};} byte[] unpackLittleEndian(int x){ return new byte[] {(byte)(x>>> 0),(byte)(x>>> 8),(byte)(x>>> 16),(byte)(x>>> 24)};} ? 總是使用無符號右移操作符(>>>)對位進行包裝(packing),不要使用算術右移操作符(>>)。 在這忙忙碌碌的這段時間里,經過老師的輔導,迅速的將一點沒有學的JAVA基礎搞定了!有了基礎學習還是好,萬事開頭難這句話說的太對了,學計算機語言我覺得記憶好的方法就是多打代碼,課前預習,課堂上認真聽講,把現學的方法把以前所做的作業用最簡便的方法再一次鞏固,創新最重要,在后續的學習中,得要加倍努力學習。 其實學java有不懂,要先自己思考。想清楚這句代碼是什么意思。為什么要寫在這,等等之類的。等你真的搞不明白的時候,就一定要向老師咨詢,不要感到有什么丟人的。因為不會是很正常的事。并不是每個人都是天才,一學就會,一學就能運用自如的。學java有一點是非常重要的,就是練習。一段代碼要不停的敲,多敲幾遍,尤其是自己不熟悉或者不熟練的代碼,更要敲。不要感覺到厭煩,其實我感覺敲代碼挺好玩的,并不是一件很枯燥的事。 老師平常布置的課后上機練習題一定要做,課后的練習題能夠讓你把新學到的知識鞏固一遍,能夠加深記憶,不會讓你在以后做題的時候感到沒一點思路。 當感覺到不會的時候,千萬不要氣餒,因為這很正常,現在的學習就是為了培養你有一個邏輯思維,為了以后開發軟件的時候有個完整,清晰的思路。 其實,總體來說。學習java很快樂。尤其是當你遇到一道自己不會的題,然后,又通過自己的努力解決了,那時候,那種心情不是用言語來表達的。就好像你遇到一個數學難題,自己解決了之后那種成就感一樣。 學java的時候一定要,放松心情,輕輕松松的來學,隨時讓自己快樂著,這樣能夠讓你能夠更快的接受java,千萬不要有什么心理負擔,因為java的特點之一就是--簡單易懂。只要自己努力到了,就一定能夠學好java。 學完了JAVA今天我們用項目案例:迷你DVD管理器來鞏固了我們所學的所有內容,通過這項目的操練,首先,1、項目用到了會使用順序、分支、循環、跳轉語句編寫程序,2、要會使用數組、操作字符串,3、會使用帶參的方法; 4、會定義類、創建和使用對象,看到這些腦袋里一片迷茫啊!不知道怎樣寫,然后想到早寫晚寫都一樣,就照著書上寫起來了,到現在還是弄不懂的就是那個對象數組,不知道怎樣去理解,抽象的把我抽暈了,有望老師來給我們補補這一章,在實現DVD的業務處理時,計算時差還是不懂,照著書上打了一遍,可還是得不到想要的結果,經過網上的搜尋與老師講解,現在已略懂一二了,在做完這項目后,真不知道當時是怎樣敲出來的,難道這就是所說的靈感!感覺很高興,現在已習慣了代碼報錯,其實代碼報錯是一件值得鼓勵的事,因為沒有錯就覺得自己什么都懂了,在學習中相信每一個人都遇到過挫折吧!但一定要想方法戰勝挫折!我的戰勝挫折方法就是不懂思考后還不懂就問,懂了以后就筆記本記下當時的解決方案!學習剛開始!后面的路很長,慢慢的去磨煉了!總結完畢! Java定義格式: 1、數據類型的強制性轉換語法: (欲轉換的數據類型)變量名稱; 2、if語句的格式: if(條件判斷) 語句; 3、if語句的格式: if(條件判斷){ 語句1; 語句2; … 語句3; } 4、if…else語句的格式: if(判斷條件){ 語句主體1; } else { 語句主體2; } 5、條件語句格式: 條件判斷?表達式1:表達式2; 即: If(條件判斷){ 變量 x=表達式1; } Else { 變量x=表達式2; } 6、if…else if…else語句格式: if(判斷條件1){ 語句主體1; } else if(判斷條件2){ 語句主體2; } … //多個else if語句 Else { 語句主體3; } 7、switch語句格式: switch(表達式){ case 選擇值1:語句主體1; break; case 選擇值2:語句主體2; break; …… case 選擇值n:語句主體n; break; default: 語句主體; } 8、while循環語句格式: while(判斷條件){ 語句1; 語句2; …… 語句n; } 9、do……while語句格式: do { 語句1; 語句2; …… 語句n; }while(判斷條件) 10、for循環語句格式: for(賦值初值:判斷條件:賦值增減量){ 語句1; …… 語句n; } 11、break語句格式: for(賦值初值:判斷條件:賦值增減量){ 語句1;12、13、14、15、16、17、18、19、20、21、語句2; …….break; …… //若執行break語句,此塊內的語句都不再執行 語句n; } continue語句格式: for(賦值初值:判斷條件:賦值增減量){ 語句1; 語句2; …… Continue;//若執行continue語句,此塊內的語句不再執行 …… 語句n; } 一維數組的聲明與分配內存格式: 數據類型 數組名[]; //聲明一維數組 數組名=new 數據類型[個數]; //分配內存給數組 聲明數組的同時分配內存格式: 數據類型 數組名[]=new 數據類型[個數] 數組長度的取得格式: 數組名.length 數組初值的賦值格式: 數據類型 數組名[]={初值0,初值1,…,初值n}; 二維數組的聲明格式: 數據類型 數組名[][]; 數據名=new 數據類型[行的個數][列的個數]; 二維數組色聲明及分配內存格式: 數據類型 數據名[][]=new 數據類型[行的個數][列的個數]; 二維數組初值的賦值格式: 數據類型 數組名={{第0行初值},{第1行初值},…… {第n行初值} }; 取得二維數組的行數與特定行的元素的個數格式: 數組名.length //取得數組的行數 數組名[行的索引].length //取得特定行元素的個數 聲明方法并定義內容格式: 返回值類型 方法名稱(類型 參數1,類型 參數2,…){ 程序語句; return 表達式;22、23、24、25、26、27、28、} 類的定義格式: class 類名稱 { 數據類型 屬性; …… 返回值的數據類型 方法名稱(參數1,參數2…){ 程序語句; return 表達式; } } 對象的產生格式: 類名 對象名=new 類名(); 訪問對象中某個變量或方法格式: 訪問對象:對象名稱.屬性名 訪問方法:對象名稱.方法名()封裝類中的屬性或方法格式: 封裝屬性:private 屬性類型 屬性名 封裝方法:private 方法返回類型 方法名稱(參數)構造方法的定義格式: class 類名稱 { 訪問權限 類名稱(類型1 參數1,類型2 參數2,…){ 程序語句; … //構造方法沒有返回值 } } 定義內部類格式: 標識符 class 外部類名稱 { //外部類的成員 標識符 class 內部類的名稱 { //內部類的成員 } } 類的繼承格式 class父類 //定義父類 { } class 子類 extends 父類 //用extends關鍵字實現類的繼承 {29、30、31、32、33、34、35、} Super調用父類中的屬性或方法格式: super.父類中的屬性; super.父類中的方法(); 子類復寫父類中的方法的格式: class Super { 訪問權限 方法返回值類型 方法1(參數1) { } } class Sub extends Super { 訪問權限 方法返回值類型 方法1(參數1)//復寫父類中的方法 { } } 抽象類的定義格式: abstract class 類名稱 //定義抽象類 { 聲明數據成員; 訪問權限 返回值的數據類型 方法名稱(參數…) { } abstract 返回值的數據類型 方法名稱(參數…); //定義抽象方法,在抽象方法里,沒有定義處理的方式 } 接口的定義格式: Interface 接口名稱 //定義抽象類 { final 數據類型 成員名稱=常量; //數據成員必須賦初值 abstract 返回值的數據類型 方法名稱(參數…); //抽象方法,注意在抽象方法里,沒有定義處理的方式 } 接口的實現格式: class 類名稱 implements 接口A,接口B //接口的實現 { …… } 接口的擴展格式: Interface 子接口名稱 extends 父接口1,父接口2,… { …… } 異常處理的語法格式: try36、37、38、39、40、41、{ 要檢查的程序語句; … } catch(異常類 對象名稱){ 異常發生時的處理語句; } finally { 一定會運行到的程序代碼; } 拋出異常的語法格式: Throw 異常類實例對象; 由方法拋出異常格式: 方法名稱(參數…)throws 異常類1,異常類2,… 編寫自定義異常類格式: class 異常名稱 extends Exception { …… } Package的聲明格式: Package package名稱; package的導入格式: import package名稱.類名稱; 由鍵盤輸入數據基本形式格式: Import java.io.*;Public class class_name //類名 { Public static void main(String args[])throws IOException { BufferedReader buf;//聲明buf為BufferedReader類的變量 String str;//聲明str為String類型的變量 …… Buf=new BufferedReader(new InputStreamReader(System.in));//產生buf對象 Str=buf.readLine(); //讀入字符串至buf …… } } Java實驗 1.調試HelloWorld程序 2.this,super,get ,set,把課本90頁程序4.7中的name改成私有變量 3.繼承,重寫,父類引用指向子類對象 4.驗證數組Arrays類和Collection類 5.編寫一個自己的異常類并捕獲之。 6.編寫一個類,將該類的幾個對象裝入TreeSet容器中,并將該容器的內容通過輸出流寫入文件中。 前三章重點 0.java的數據類型:四類八種-(1)布爾類型Boolean;(2)字符類型char;(3)整數byte,short,int,long;(4)浮點類型:float,double;1.面向對象的3個基本特征:封裝,繼承,多態。 2.構造方法和普通方法的區別:對構造方法而言,它有以下特性---(1)方法名必須與要創建對象的類名相同。(2)不允許聲明返回類型,即使聲明為void也不被允許。 3.this關鍵字:是一個引用,this引用指向的是其本身所在方法的當前對象。this的使用方法:(1)調用成員變量;(2)可以用this()調用其他構造函數。 4.java中只對類成員變量進行自動初始化,而方法內部的局部變量在使用前必須手動初始化。 5.static 關鍵字:可用來修飾類的成員變量和成員方法,需要注意兩點--(1)靜態方法不能調用類的非靜態方法,不能訪問類的非靜態變量。(2)靜態方法和靜態變量(非私有的)可以有兩種調用方式,一是實例對象調用,二是類名直接調用。 6.類成員訪問控制修飾符public、private、default(可不寫,即缺省狀態)、protected的使用:public-公用的;private-私有的,只在定義它的類內部使用;default-可以被同一包中的類訪問;protected-既可以被同一包中的類訪問,也可以被不在同一包中的子類訪問。 7.方法的重載:指方法名相同,而方法的參數列表不相同。參數列表不同有三層意思:(1)參數類型不同。(2)參數順序不同。(3)參數個數不同。另外需注意,在同一個類中,當方法名和參數列表都相同時,訪問控制修飾符或方法返回類型不相同并不是方法的重載,而且這種情況在java中是不被允許的。 第四五章重點 1.繼承:需使用關鍵字extends.在使用繼承時需注意--(1)每個子類只能定義一個超類(父類),即extends后面應且僅應跟一個類名作為該類的父類。(2)父類中的私有屬性和私有方法不能被繼承。 2.方法的重寫:即子類對超類中的方法保持方法名、返回類型和參數列表不變,重寫了方法體,使子類和超類完成不同的工作。重寫需注意下面幾個關鍵點:(1)超類中的私有方法不能被重寫。(2)訪問限制符強度由低到高依次是:public、protected、default、private,在重寫過程中,如果子類和父類中方法的返回值、方法名及方法的參數列表都相同,這時,要求子類中該方法的訪問限制符強度不能超過父類的。即如果父類中為public時,子類也只能為public,而不能是余下的三種。 3.重載(overload)和覆蓋(override)的區別:(1)重載—發生在一個類的內部或子類與父類之間,要求方法名相同而參數列表不一樣。(2)覆蓋—只能發生在繼承過程中,要求子類方法的返回類型,方法名和參數列表同父類的都相同,而方法體不一樣。 4.構造器的調用順序:先祖先,再客人,最后自己。 5.多態:指在類繼承中子類和父類中可以有同名但意義或實現方式不同的屬性和方法。分為:覆蓋和重載。多態的優點:因為多態,可以在程序中對類進行擴展,而不需改變那些操作基類接口的方法。 6.動態綁定:指在代碼執行期間,判斷所引用對象的實際類型,根據其實際類型調用相應方法。動態綁定存在的三個必要條件--(1)要有繼承;(2)要有重寫(覆蓋);(3)父類引用指向子類對象(向上轉型)。 7.Object中常用的方法總結:toString();wait();equals();notify();notifyAll();hashCode();getClass();clone();finalize();(呵呵,盡可能記幾個,以防老師讓咱們列舉)注:java中Object類是所有類的父類,即java中所有的類都有上述9種方法。 8.對象的比較:注意關鍵字instanceof的使用。 9.抽象類: 抽象方法—用關鍵字abstract修飾的方法,該方法只需方法的聲明,而不需方法的實現(即無方法體)。 抽象類——至少包含一個抽象方法的類,也用abstract關鍵字聲明。(注:(1)抽象類中可以有一些具體方法。(2)抽象類不能實例化。(3)子類繼承抽象類必須實現其抽象方法。) 10.接口: (1)可以看成是高度抽象的抽象類,但是接口不是類。 (2)用關鍵字interface來聲明接口,用關鍵字imlpements來實現接口。 (3)接口不能有具體方法,不能有實例數據,但可以定義常量。 (4)實現接口的非抽象類必須實現接口的所有方法。 (5)每個類可以實現多個接口,這些接口用逗號隔開,同時,一個接口可以被多個類實現。 第六章:重點看一下實驗四 1.容器——Collection(接口)和Map(接口).Collection——Set(接口)和List(接口)。其中,List必須保持元素的特定順序,常見的實現類有ArrayList和LinkedList;Set不能有重復元素,常見的實現類有HashSet和TreeSet。 Map——一組成對的“鍵值對”對象,即其元素是成對的對象,常見的實現類有HashMap和TreeMap。 第七章 1.異常類的根類是Throwable類,它的兩個直接子類是Error類和Exception類。 2.異常中常用的5個關鍵字為:try,catch,finally,throw,throws.其中,try和catch:用于捕獲異常;finally:無論try塊中的異常是否拋出,finally中的代碼塊總能被執行;throw:拋出異常;throws:聲明異常。 3.“未被檢查的異常(Unchecked Exceptions)”和“受檢查的異常(Checked Exceptions)”—— Unchecked Exceptions :編譯器不檢查方法是否處理或拋出的異常,即不做處理,編譯時不報錯。 Checked Exceptions:受編譯器檢查的異常,即不做處理編譯時通不過。 4.常見的幾種Checked Exceptions:ClassNotFoundExceptionIOExceptionInterruptedExceptionFileNotFoundException.(盡可能的記幾個吧,以防不測)第八章 1.流--字節流和字符流; 流--節點流和處理流。 2.所有的輸入流都是從抽象類InputStream和Reader繼承而來。所有輸出流都是從抽象類OutputStream和Writer繼承而來。3.字節流:InputStream和OutputStream;字符流:Reader和Writer; 4.節點流:直接與文件等底層打交道,如FileInputStreamFileOutputStreamFileReaderFileWriter.處理流:相當于包裝流,套在節點流上,方便數據處理。相關一些用法,具體參考最后一次實驗。 調用父類構造方法 ? 在子類的構造方法中可使用super(argument_list)語句調用父類的構造方法 ? 如果子類的構造方法中沒有顯示地調用父類構造方法,也沒有使用this關鍵字調用重載的其它構造方法,則系統默認調用父類無參數的構造方法 ? 如果子類構造方法中既未顯式調用父類構造方法,而父類中又沒有無參的構造方法,則編譯出錯 1public class Person { 3private String name; 4private int age;private Date birthDate; 7public Person(String name, int age, Date d){ 8this.name = name; 9this.age = age; 10this.birthDate = d; 11} 12public Person(String name, int age){ 13this(name, age, null); 14} 15public Person(String name, Date d){ 16this(name, 30, d); 17} 18public Person(String name){ 19this(name, 30);} 21// …… 22} 1public class Student extends Person { 2private String school; 4public Student(String name, int age, String s){ 5super(name, age); 6school = s; 7} 8public Student(String name, String s){ 9super(name); 10school = s; 11} 12public Student(String s){ // 編譯出錯: no super()13school = s; 14} 15} 對象構造和初始化細節 ? 分配存儲空間并進行默認的初始化 ? 按下述步驟初始化實例變量 1.綁定構造方法參數 2.如有this()調用,則調用相應的重載構造方法,然后跳轉到步驟5 3.顯式或隱式追溯調用父類的構造方法(Object類除外) 4.進行實例變量的顯式初始化操作 5.執行當前構造方法的方法體 ==操作符與equals方法 ==操作符與equals方法的區別: ? 引用類型比較引用;基本類型比較值; ? equals()方法只能比較引用類型,“==”可以比較引用類型及基本類型; ? 特例:當用equals()方法進行比較時,對類File、String、Date及封裝類(Wrapper Class)來說,是比較類型及內容而不考慮引用的是否是同一個實例; ? 用“==”進行比較時,符號兩邊的數據類型必須一致(可自動轉換的基本數據類型除外),否則編譯出錯; 由裝箱引發的——Integer比較的來龍去脈 前置知識: 眾所周之,java是保留了int,char等基本數據類型的,也就是說int類型的并不是對象,然而有些方法卻需要object 類型的變量,所以java使用了裝箱機制,我們可一自豪的這樣聲明一個整型變量:Integer a = new Integer(10);那么整型的a也就是對象了,那這句是什么意思呢:Integer a= 10;java中可以這樣聲明一個對象嗎?當然不是,從jdk1.5后,java實現了自動裝箱,也就是自動將Integer a =10 中的int類型的10轉化為了 Integer類型。好,有了前面的只是我們且先看一個題目: Integer a = 127; Integer b = 127; Integer c = 128; Integer d = 128; System.out.println(a==b); System.out.println(c==d); 答案是什么呢? 如果您回答true,false,那么很遺憾的告訴你,哈哈,其實你答對了??! 那我們暈了就相差1的兩個數為啥走向了“反目成仇”的地步呢?憑啥127等于127,我128就不等于128呢?且聽我慢慢道來,Integer a =127,Integer a=128。 127,128應該不會造成什么差異吧,難道是自動裝箱的過程有貓膩?找下源碼看看: private static class IntegerCache { private IntegerCache(){} static final Integer cache[] = new Integer[-(-128)+ 127 + 1];static { for(int i = 0;i < cache.length;i++) cache[i] = new Integer(i128); } 這是用一個for循環對數組cache賦值,cache[255] = new Integer(255-128),也就是newl一個Integer(127),并把引用賦值給cache[255],好了,然后是Integer b= 127,流程基本一樣,最后又到了cache[255] = new Integer(255-128),這一句,那我們迷糊了,這不是又new了一個對象127嗎,然后把引用賦值給cache[255],我們比較這兩個引用(前面聲明a的時候也有一個),由于是不同的地址,所以肯定不會相等,應該返回false??!呵呵,這么想你就錯了,請注意看for語句給cache[i]初始化的時候外面還一個{}呢,{}前面一個大大的static關鍵字大咧咧的杵在哪呢,對靜態的,那么我們就可以回想下static有什么特性了,只能初始化一次,在對象間共享,也就是不同的對象共享同一個static數據,那么當我們Integer b = 127的時候,并沒有new出一個新對象 來,而是共享了a這個對象的引用,記住,他們共享了同一個引用?。。敲次覀冞M行比較a==b時,由于是同一個對象的引用(她們在堆中的地址相同),那當然返回true了??! 然后我們在看Integer c = 128;Integer d = 128;這兩句?,F在不用我說就應該能明白了吧,當數據不再-128到127之間時,是不執行return IntegerCache.cache[i + offset];這句的,也就是不會返回一個static的引用,而是執行了return new Integer(i);于是當 Integer d = 128 時,又會重新返回一個引用,兩個不同的引用 在做c==d 的比較時當然返回false了! 下面附上本程序的字節碼以供喜歡底層的讀者參考: Compiled from “CompareInteger.java” public class CompareInteger extends java.lang.Object{ public CompareInteger(); Code: 0:aload_0 1:invokespecial#1;//Method java/lang/Object.“ public static void main(java.lang.String[]); Code: 0:bipush 127 2:invokestatic#2;//Method java/lang/Integer.valueOf:(I)Ljava/lang/Int eger; 5:astore_1 6:bipush 127 8:invokestatic#2;//Method java/lang/Integer.valueOf:(I)Ljava/lang/Int eger; 11: astore_2 12: sipush 128 15: invokestatic#2;//Method java/lang/Integer.valueOf:(I)Ljava/lang/Int eger; 18: astore_3 19: sipush 128 22: invokestatic#2;//Method java/lang/Integer.valueOf:(I)Ljava/lang/Int eger; 25: astore 4 27: getstatic#3;//Field java/lang/System.out:Ljava/io/PrintStream; 30: aload_1 31: aload_2 32: if_acmpne39 35: iconst_1 36: goto40 39: iconst_0 40: invokevirtual#4;//Method java/io/PrintStream.println:(Z)V43: getstatic#3;//Field java/lang/System.out:Ljava/io/PrintStream; 46: aload_3 47: aload4 49: if_acmpne56 52: iconst_1 53: goto57 56: iconst_0 57: invokevirtual#4;//Method java/io/PrintStream.println:(Z)V60: return } 評論:呵呵,這么想你就錯了,請注意看for語句給cache[i]初始化的時候外面還一個{}呢,{}前面一個大大的static關鍵字大咧咧的杵在哪呢,對靜態的,那么我們就可以回想下static有什么特性了,只能初始化一次,在對象間共享,也就是不同的對象共享同一個static數據,那么當我們Integer b = 127的時候,并沒有new出一個新對象來,而是共享了a這個對象的引用,記住,他們共享了同一個引用??! 呵呵,博主我被你這句話小小的誤導了一下,其實你這里說的原理沒錯,但是把位置說錯了,這段代碼只是初始化cache: static { for(int i = 0;i < cache.length;i++) cache[i] = new Integer(i-128); } 但真正讓cache[i]為static變量的是這句代碼: static final Integer cache[] = new Integer[-(-128)+ 127 + 1];第二篇:JAVA總結專題
第三篇:Java格式總結
第四篇:Java總結
第五篇:java總結