網上轉來的
昨天整整一天,我都都呆在圖書里。本打算找一些書學習“正則表達式”,很失望,沒找到有這部分的內容的書。發現了一本《Java深入解析》,其中涉及了很多平時沒有注意的一些誤區,也許開發的時候用不上,但是對這些概念卻不能模糊。書中的內容還是很有用處,這里摘要了一些筆記。
1 在Java中,沒有 goto
語句。因為大量使用 goto
語句會降低程序的可讀性和可維護性,所以Java語言取消了 goto
的使用。同時,為了避免程序員自行使用 goto
所帶來的混亂,Java語言仍將 goto
定義為一個關鍵字,但是沒有定義任何語法,故稱為“保留字”。
2 true
、 false
和 null
在IDE中雖然以不同的顏色顯示了, 但是并不是關鍵字,而是“字面常量”,就和 String
類型的 abc
一樣。
3 定義名稱時盡量避免使用 $
,因為 編譯器在對.java文件進行編譯的時候,會將”$”編譯成頂層類型與底層類型的連接符。 見下例:
使用$定義變量名
package com.laixintao.Test;public class Outer$Inner { public static void main(String[] args) { Outer o = new Outer(); Outer.Inner i = o.new Inner(); i.innerPRint(); }}class Outer { class Inner { void innerPrint() { System.out.println("Inner Print!"); } }}
packagecom.laixintao.Test; publicclassOuter$Inner{ publicstaticvoidmain(String[]args){ Outero=newOuter(); Outer.Inneri=o.newInner(); i.innerPrint(); }}classOuter{classInner{ voidinnerPrint(){ System.out.println("Inner Print!"); } }} |
在編譯( javac Test3.java
)這段代碼的時候,編譯器會報以下錯誤: Test.java:12: 錯誤: 類重復: com.laixintao.Test.Outer.Inner class Inner{ ^
4 Unicode轉義字符處理的非常早,在解析程序之前。 例如:
Unicode編譯錯誤
// char c1 = '/u00a';// char c2 = '/u00d';
// char c1 = '/u00a'; // char c2 = '/u00d'; |
在程序中出現這兩行代碼編譯報錯。這兩個Unicode碼分別表示”換行”和”回車”,所以,在編譯器編譯的時候,代碼是這樣的:
Unicode編譯
// char c1 = '';// char c2 = '';
// char c1 = '';// char c2 = ' ' ; |
5 Unicode碼使用16位字符編碼,在Java中用 char
類型來表示。現在Unicode已經擴展到一百萬個字符,超出16位限制的成為增補字符。 所有增補字符都不能用字符常量來表示。
6 當 short
, byte
, char
參加運算時,結果為 int
型,而非與較高的類型相同。
如果變量是 byte
, short
, byte
類型,當對其賦予編譯時期的常量,而該常量又沒有超過變量的取值范圍時,,編譯器就可以進行隱式的收縮轉換。這種隱式的收縮轉換是安全的,因為該收縮轉換只適用于變量的賦值,而不適用于方法調用語句,即不適用于方法調用時的參數傳遞。(詳見 java中默認類型轉換的小問題 )
7 注意 char
類型,這是一個無符號類型。因此, char
與 short
或 char
與 byte
之間的轉換必須顯示地使用類型轉換。 從 byte
到 char
的轉換為擴展收縮轉換,該轉換比較特殊,即先將 byte
擴展轉換到 int
,然后再收縮到 char
。
8 在整型數據間的擴展轉換中,如果操作數事 char
類型(無符號類型),則進行無符號擴展,擴展位為0.如果操作數是 byte
, short
或 int
(有符號類型),則進行有符號擴展,擴展位為該變量的符號位。
9 整型數據之間的收縮轉換,僅僅是截斷并丟棄高位,不做任何其他處理。 1 0.1+0.2不等于0.3.System.out.println((double)0.1+(double)0.2);
這條語句的輸出結果是/ /http://www.pprar.com0.30000000000000004
。因為計算機使用二進制來存儲數據,而很多小數都不能夠準確地使用二進制來表示(事實上,大多數地小數都是近似的),就像使用十進制小數不能準確地表示1/3這樣地分數一樣。大多數地浮點型,在計算機中只是近似地存儲其值,而不像整型那樣準確地存儲。又例,這是一個死循環: for(float f = 10.1f;f != 11;f+=0.1f){}
10 float
類型可以保留7~8個有效數字,而 double
類型可以保留15~16個有效數字,因而當 int
類型或long類型數值多于 double
或 float
地有效數字時,該值的一些最低有效位就會丟失,從而造成精度丟失,這時,就會采用IEEE754最近舍入模式,提取與該整型值最接近的浮點值。 盡管整型向浮點型的轉換屬于擴展轉換,但當數值很大或很小(絕對值很大)時,就會產生一定的精度丟失。
11 i+++j
如何計算?(這個問題在C/C++)中討論是沒有多大意義的,因為C/C++依賴于實現的硬件結構,不同的環境結果也會不同。不過在Java中,這個結果是固定的,不受其運行的硬件環境與平臺的影響) 答:根據貪心規則,前置++優于后置++,結果是 (i++)+j
12 i++和++i其實都是先+1,再賦值。++i,沒什么好說的;i++,以 j=i++;
為例在底層的實現是: temp = i;i = i + 1; j = temp;
所以, i=15;i=i++;
這個表達式的結果是15.(因為加一之后又執行了一次賦值,從16變回15)
13 +0與-0在浮點類型變量存儲中,符號位是不同的。當-0和+0參與浮點類型的相關運算(例如相除與求余運算)時,可以產生不同的結果。
14 浮點的相除與求余運算不同與整型的相除與求余運算,當除數為0時,浮點運算不會產生 ArithmeticException
異常。
15 String
類是非可變類,其對象一旦創建,就不可銷毀。 String
類那些看似修改字符序列的方法實際上都是返回新創建的 String
對象,而不是修改自身對象。
16 由于 String
對象是不可改變的,因此具有線程安全性,可以自由地實現共享。
17 在 String
類內部,是使用一個字符數組( char[]
)來維護字符序列的。 String
的最大長度也就是字符數組的最大長度,理論上最大長度為int類型的最大值,即2147483647.在實際中,一般可獲取的最大值小于理論最大值。
18 main()
方法在表現行為上,與其他方法基本相同,可以重載,由其他方法調用,繼承,隱藏,也可以拋出異常,帶有類型參數。我們也可以在一個程序中通過反射來調用 main方法
(或其他方法)。 2當兩個或多個方法的名稱相同,而參數列表不同時,這幾個方法就構成了重載。重載方法可以根據參數列表對應的類型與參數的個數來區分,但是,參數的名稱、方法的返回類型,方法的異常列表與類型參數不能作為區分重載方法的條件。
19 究竟選擇哪個方法調用,順序是這樣的:
20 重寫和隱藏的本質區別是:重寫是動態綁定的,根據運行時引用所指向對象的實際類型來決定調用相關類的成員。而隱藏是靜態綁定的,根據編譯時引用的靜態類型來決定調用的相關成員。換句話說,如果子類重寫了父類的方法,當父類的引用指向子類對象時,通過父類的引用調用的是子類方法。如果子類隱藏了父類的方法(成員變量),通過父類的引用調用的仍是父類的方法(成員變量)。
21 構造器是遞歸調用的,子類的構造器會調用父類的構造器,直到調用Object類的構造器為止。
22 構造器沒有創建對象,構造器是使用new創建對象時由系統調用的,用來初始化類的實例成員。從順序上說,先是創建對象,然后再調用構造器的。 (構造器并沒有產生新的對象)
23 默認的構造器不為空,該構造器會調用父類的無參構造器,并可能執行實例成員變量的初始化。所以,默認的構造器至少調用了父類的構造器,它做的工作還可能更多,包括實例變量聲明初始化與實例初始化塊,都是在構造器中執行的。
24 當==或!=運算符的兩個操作數的類型一個是基本數據類型,另一個是包裝類引用類型時,將引用類型拆箱轉換為基本數據類型,然后比較兩個基本數據類型的值是否相等。
25 在Java中,數組也是類,數組聲明的引用變量指向數組類型的對象。所有的數組都繼承 Object
類,并且實現了 java.lang.Cloneable
與 java.io.Serializable
接口。數組的成員包括變量 length
(隱式存在)與從Object類繼承的成員。 Cloneable
與 Serializable
是兩個標記的接口,這兩個接口中沒有顯式聲明任何成員。
26 接口是完全抽象的設計,不能實例化。使A用 new
方式創建的借口類型,實際上是創建了一個匿名類,該匿名類實現了接口類型。
27 如果兩個接口聲明了相同的變量x,則當某接口同時繼承這兩個接口,或者某類同時實現這兩個接口時,通過簡單名稱訪問會產生編譯錯誤。
28 如果兩個接口中聲明了相同名稱的方法m,并且兩個方法沒有構成重載,則當某接口能夠同時繼承這兩個接口,或者某類能夠同時繼承這兩個接口時,必須存在一種方法簽名,使得該簽名同時為兩個m方法簽名的子簽名,并且在方法的返回類型上,必須存在一種類型,使得該類型同時為兩個m方法返回類型的可替換類型。
新聞熱點
疑難解答