夜光:Java成神之路(三)擅長的語言

夜光序言:

 

 

我多麼想等你回來,但我卻先白了頭

 

 

 

 
 
正文:
 
                                              以道御術 / 以術識道

 


 


 

方法重寫的規則:

 
1.參數列表必須完全與被重寫方法的一致,返回類型必須完全與被重寫方法的返回類型一致。
 
2.構造方法不能被重寫,聲明爲 final 的方法不能被重寫,聲明爲 static 的方法不能被重寫,但是能夠被再次聲明。
 

3.訪問權限不能比父類中被重寫的方法的訪問權限更低。

 
4.重寫的方法能夠拋出任何非強制異常(UncheckedException,也叫非運行時異常),無論被重寫的方法是否拋出異常。

 

但是,重寫的方法不能拋出新的強制性異常,或者比被重寫方法聲明的更廣泛的強制性異常,反之則可以

 
 
 

 

8. 爲什麼函數不能根據返回類型來區分重載?

 

因爲調用時不能指定類型信息,編譯器不知道你要調用哪個函數。

 

例如:

 

1float max(int a, int b);
 
2int max(int a, int b);
 
當調用 max(1, 2);時無法確定調用的是哪個,單從這一點上來說,僅返回值類型不同的重載是不應該允許的。
再比如對下面這兩個方法來說,雖然它們有同樣的名字和自變量,但其實是很容易區分的:
 
1void f() {}
 
2int f() {}
 
 
若編譯器可根據上下文(語境)明確判斷出含義,比如在 int x=f()中,那麼這樣做完全沒有問題。
 
然而,我們也可能調用一個方法,同時忽略返回值;我們通常把這稱爲“爲它的副作用去調用一個方法”,因爲我們關心的不是返回值,而是方法調用的其他效果。
 
所以假如我們像下面這樣調用方法: f();
 
Java 怎樣判斷 f()的具體調用方式呢?而且別人如何識別並理解代碼呢?
 
由於存在這一類的問題,所以不能。
 
 
函數的返回值只是作爲函數運行之後的一個“狀態”,他是保持方法的調用者與被調用者進行通信的關鍵。
 
並不能作爲某個方法的“標識”

 


 

9. char 型變量中能不能存儲一箇中文漢字,爲什麼?

 

char 類型可以存儲一箇中文漢字,因爲 Java 中使用的編碼是 Unicode
 
(不選擇任何特定的編碼,直接使用字符在字符集中的編號,這是統一的唯一方法)
 
一個 char 類型佔 2 個字節(16 比特),所以放一箇中文是沒問題的。
 
 
補充:使用 Unicode 意味着字符在 JVM 內部和外部有不同的表現形式,在 JVM 內部都是 Unicode,當這個字符被從 JVM 內部轉移到外部時(例如存入文件系統中),需要進行編碼轉換。
 
所以 Java 中有字節流和字符流,以及在字符流和字節流之間進行轉換的轉換流
 
 
如 InputStreamReader OutputStreamReader,這兩個類是字節流和字符流之間的適配器類,承擔了編碼轉換的任務;
 
 
對於 C 程序員來說,要完成這樣的編碼轉換恐怕要依賴於 union(聯合體/共用體)共享內存的特徵來實現了。

 


 

10. 抽象類(abstract class)和接口(interface)有什麼異同?

不同:

 

抽象類:

1.抽象類中可以定義構造器
 
2.可以有抽象方法和具體方法
 
3.接口中的成員全都是 public 的
 
4.抽象類中可以定義成員變量
 
5.有抽象方法的類必須被聲明爲抽象類,而抽象類未必要有抽象方法
 
6.抽象類中可以包含靜態方法
 
7.一個類只能繼承一個抽象類
 

 

接口:

 
1.接口中不能定義構造器
 
2.方法全部都是抽象方法
 
3.抽象類中的成員可以是 private、默認、protected、public
 
4.接口中定義的成員變量實際上都是常量
 
5.接口中不能有靜態方法
 
6.一個類可以實現多個接口     兄弟,對比看下繼承,所以我們程序員一般都是面向接口開發
 
 

 

相同:

 
1.不能夠實例化
 
2.可以將抽象類和接口類型作爲引用類型
 
3.一個類如果繼承了某個抽象類或者實現了某個接口都需要對其中的抽象方法全部進行實現,否則該類仍然需要被聲明爲抽象類

 

 

 


 

 

11. 抽象的(abstract)方法是否可同時是靜態的(static), 是否可同時是本地方法(native),是否可同時被 synchronized

 

都不能。

 
抽象方法需要子類重寫,而靜態的方法是無法被重寫的,因此二者是矛盾的。
 
本地方法是由本地代碼(如 C 代碼)實現的方法,而抽象方法是沒有實現的,也是矛盾的。
 
 
synchronized 和方法的實現細節有關, 抽象方法不涉及實現細節,因此也是相互矛盾的。

 


 

12. 闡述靜態變量和實例變量的區別?

 

靜態變量: 是被 static 修飾符修飾的變量,也稱爲類變量,它屬於類,不屬於類的任何一個對象,一個類不管創建多少個對象,靜態變量在內存中有且僅有一個拷貝;

 

實例變量: 必須依存於某一實例,需要先創建對象然後通過對象才能訪問到它。靜態變量可以實現讓多個對象共享內存

 


 

13. ==和 equals 的區別?

equals 和== 最大的區別是一個是方法一個是運算符。

 
==:如果比較的對象是基本數據類型,則比較的是數值是否相等;如果比較的是引用數據類型,則比較的是對象的地址值是否相等。
 

 

equals():用來比較方法兩個對象的內容是否相等。

 

 
注意:equals 方法不能用於基本數據類型的變量,如果沒有對 equals 方法進行重寫,則比較的是引用類型的變量所指向的對象的地址
 

 

 

14. break 和 continue 的區別?

 

break 和 continue 都是用來控制循環的語句。
 
break 用於完全結束一個循環,跳出循環體執行循環後面的語句。
 
continue 用於跳過本次循環,執行下次循環。
 
 

 

15. String s = "Hello";s = s + " world!";這兩行代碼執行後,原始的 String 對象中的內容到底變了沒有?

 

答案是沒有

 
因爲 String 被設計成不可變(immutable)類,所以它的所有對象都是不可變對象。在這段代碼中,s 原先指向一個 String 對象,內容是 "Hello",然後我們對 s 進行了“+”操作,那麼 s 所指向的那個對象是否發生了改變呢? --沒有
 
 

這時,s 不指向原來那個對象了,而指向了另一個 String 對象,內容爲"Hello world!",原來那個對象還存在於內存之中,只是 s 這個引用變量不再指向它了。

 

通過上面的說明,我們很容易導出另一個結論,如果經常對字符串進行各種各樣的修改,或者說,不可預見的修改,那麼使用 String 來代表字符串的話會引起很大的內存開銷。
 
因爲 String 對象建立之後不能再改變,所以對於每一個不同的字符串,都需要一個 String 對象來表示。這時,應該考慮使用 StringBuffer 類,它允許修改,而不是每個不同的字符串都要生成一個新的對象。並且,這兩種類的對象轉換十分容易。
 
 

同時,我們還可以知道,如果要使用內容相同的字符串,不必每次都 new 一個 String。

 
 
例如我們要在構造器中對一個名叫 s 的 String 引用變量進行初始化,把它設置爲初始值,應當這樣做
 
public class Demo {
 private String s;
  ...
 s = "Initial Value";
 ...
}
而非
s = new String("Initial Value");

 

後者每次都會調用構造器,生成新對象,性能低下且內存開銷大,並且沒有意義,因爲 String 對象不可改變,所以對於內容相同的字符串,只要一個 String 對象來表示就可以了。
 
也就說,多次調用上面的構造器創建多個對象,們的 String 類型屬性 s 都指向同一個對象。
 
 
上面的結論還基於這樣一個事實:對於字符串常量,如果內容相同,Java 認爲它們代表同一個 String 對象。
而用關鍵字 new 調用構造器,總是會創建一個新的對象,無論內容是否相同
 
至於爲什麼要把 String 類設計成不可變類,是它的用途決定的。其實不只 String,很多 Java 標準類庫中的類都是不可變的。
 
在開發一個系統的時候,我們有時候也需要設計不可變類,來傳遞一組相關的值,這也是面向對象思想的體現。
不可變類有一些優點,比如因爲它的對象是隻讀的,所以多線程併發訪問也不會有任何問題。
 
 
當然也有一些缺點,比如每個不同的狀態都要一個對象來代表,可能會造成性能上的問題。
 
所以 Java 標準類庫還提供了一個可變版本,即 StringBuffer。
 
 
 
 
 
 
 

 

 

三、Java 中的多態

 
 

1. Java 中實現多態的機制是什麼?

靠的是父類或接口定義的引用變量可以指向子類或具體實現類的實例對象
 
而程序調用的方法在運行期才動態綁定,就是引用變量所指向的具體實例對象的方法
 

也就是內存里正在運行的那個對象的方法,而不是引用變量的類型中定義的方法。

 
 
 

 

 

 

四、Java 的異常處理

 

 

1. Java 中異常分爲哪些種類

1)按照異常需要處理的時機分爲編譯時異常(也叫強制性異常)也叫 CheckedException 和運行時異常(也叫非強制性異常)也叫 RuntimeException。
 
只有 java 語言提供了 Checked 異常,Java 認爲 Checked 異常都是可以被處理的異常,所以 Java 程序必須顯式處理 Checked 異常。
 
如果程序沒有處理 Checked 異常,該程序在編譯時就會發生錯誤無法編譯。
 

這體現了 Java 的設計哲學:沒有完善錯誤處理的代碼根本沒有機會被執行。對 Checked 異常處理方法有兩種:

 
1 當前方法知道如何處理該異常,則用 try...catch 塊來處理該異常。
 
2 當前方法不知道如何處理,則在定義該方法是聲明拋出該異常。
 
運行時異常只有當代碼在運行時才發行的異常,編譯時不需要 try catch。
 
Runtime 如除數是 0 和數組下標越界等,其產生頻繁,處理麻煩,若顯示申明或者捕獲將會對程序的可讀性和運行效率影響很大。
 
所以由系統自動檢測並將它們交給缺省的異常處理程序。當然如果你有處理要求也可以顯示捕獲它們。
 
 

 


 

2. 調用下面的方法,得到的返回值是什麼

1. public int getNum(){
2. try {
3. int a = 1/0;
4. return 1;
5. } catch (Exception e) {
6. return 2;
7. }finally{
8. return 3;
9. }

 

代碼在走到第 3 行的時候遇到了一個 MathException,這時第四行的代碼就不會執行了,代碼直接跳轉到 catch語句中,走到第 6 行的時候,異常機制有這麼一個原則如果在 catch 中遇到了 return 或者異常等能使該函數終止的話
 
那麼有 finally 就必須先執行完 finally 代碼塊裏面的代碼然後再返回值。
 
因此代碼又跳到第 8 行,可惜第 8 行是一個 return 語句,那麼這個時候方法就結束了,因此第 6 行的返回結果就無法被真正返回。
 
 
如果 finally 僅僅是處理了一個釋放資源的操作,那麼該道題最終返回的結果就是 2。因此上面返回值是 3

 

 


 

3. error 和 exception 的區別?

 

Error 類和 Exception 類的父類都是 Throwable 類,他們的區別如下。
 
Error 類一般是指與虛擬機相關的問題,如系統崩潰,虛擬機錯誤,內存空間不足,方法調用棧溢出等。
 
對於這類錯誤的導致的應用程序中斷,僅靠程序本身無法恢復和和預防,遇到這樣的錯誤,建議讓程序終止。
 
Exception 類表示程序可以處理的異常,可以捕獲且可能恢復。遇到這類異常,應該儘可能處理異常,使程序恢復運行,而不應該隨意終止異常。
 
Exception 類又分爲運行時異常(Runtime Exception)和受檢查的異常(Checked Exception )
 
運行時異常;
 
ArithmaticException,IllegalArgumentException,編譯能通過,但是一運行就終止了,程序不會處理運行時異常,
 
出現這類異常,程序會終止。
 
 
而受檢查的異常,要麼用 try。。。catch 捕獲,要麼用 throws 字句聲明拋出,交給它的父類處理,否則編譯不會通過。
 
 

 

4. java 異常處理機制

 

Java 對異常進行了分類,不同類型的異常分別用不同的 Java 類表示,所有異常的根類爲 java.lang.Throwable,Throwable 下面又派生了兩個子類:Error 和 Exception,Error 表示應用程序本身無法克服和恢復的一種嚴重問題。
 
 
 
Exception 表示程序還能夠克服和恢復的問題,其中又分爲系統異常和普通異常,系統異常是軟件本身缺陷所導致的問題,也就是軟件開發人員考慮不周所導致的問題
 
 
軟件使用者無法克服和恢復這種問題,但在這種問題下還可以讓軟件系統繼續運行或者讓軟件死掉

 

例如,數組腳本越界(ArrayIndexOutOfBoundsException)

空指針異常(NullPointerException)

類轉換異常(ClassCastException)

 
 
普通異常是運行環境的變化或異常所導致的問題, 是用戶能夠克服的問題,例如,網絡斷線,硬盤空間不夠,發生這樣的異常後,程序不應該死掉。
 
 
java 爲系統異常和普通異常提供了不同的解決方案,編譯器強制普通異常必須 try..catch 處理或用 throws 聲明繼 續拋給上層調用方法處理,所以普通異常也稱爲 checked 異常,而系統異常可以處理也可以不處理
 
 

所以,編譯器不強制用 try..catch 處理或用 throws 聲明,所以系統異常也稱爲 unchecked 異常。

 

 

 


 

5. 請寫出你最常見的 5 個 RuntimeException

 

下面列舉幾個常見的 RuntimeException。

 
1)java.lang.NullPointerException 空指針異常;出現原因:調用了未經初始化的對象或者是不存在的對象。
 
2)java.lang.ClassNotFoundException 指定的類找不到;出現原因:類的名稱和路徑加載錯誤;通常都是程序試圖通過字符串來加載某個類時可能引發異常。
 
3)java.lang.NumberFormatException 字符串轉換爲數字異常;出現原因:字符型數據中包含非數字型字符。
 
4)java.lang.IndexOutOfBoundsException 數組角標越界異常,常見於操作數組對象時發生。
 
5)java.lang.IllegalArgumentException 方法傳遞參數錯誤。
 
6)java.lang.ClassCastException 數據類型轉換異常
 
7)java.lang.NoClassDefFoundException 未找到類定義錯誤。
 
8)SQLException SQL 異常,常見於操作數據庫時的 SQL 語句錯誤。
 
9)java.lang.InstantiationException 實例化異常。
 
10)java.lang.NoSuchMethodException 方法不存在異常。

 


 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章