Java核心技術 卷I 基礎知識 學習筆記(6)
參考:Java核心技術 卷I 基礎知識
介面,主要用來描述類具有什麼功能,而並不給出每個功能的具體實現。一個類可以實現一個或多個介面,並在需要介面的地方,隨時使用實現了相應介面的物件。介面不是類,是對類的一組需求描述,這些類要遵從介面描述的統一格式進行定義。
介面中的所有方法自動地屬於public。
介面中可以定義常量。介面不能包含例項域。
提供例項域和方法實現的任務應該由實現介面的那個類來完成。因此,可以將介面看成是沒有例項域的抽象類。
介面不是類,尤其不能使用new運算子例項化一個介面。
不能構造介面的物件,但可以宣告介面的變數。
介面變數必須引用實現了介面的類物件。
介面中的域被自動設為public static final。
如果先在一個介面中將一個方法定義為預設方法,然後又在超類或另一個介面中定義了同樣的方法。Java規則如下:
(1)超類有限。如果超類提供了一個具體方法,同名且有相同的引數型別的預設方法會被忽略。
(2)介面衝突。如果一個超介面提供了一個預設方法,另一個介面提供了同名且引數型別(不論是否預設引數)相同的方法,必須覆蓋這個方法來解決衝突。
回撥是一種常見的程式設計模式。在這種模式中,可以指出某個特定事件發生時應該採取的動作。
lambda表示式是一個可傳遞的程式碼塊,可以在以後執行一次或多次。
lambda表示式由3個部分:
- 一個程式碼塊
- 引數
- 自由變數的值,這是指非引數且不再程式碼中定義的變數。
規則:lambda表示式中捕獲的變數必須是實際上的最終變數。實際上的最終變數是指這個變數初始化之後就不會再為它賦新值。lamdba表示式與巢狀塊有相同的作用域。這裡同樣適用命名衝突和遮蔽的有關規則。在方法中,不能有兩個同名的區域性變數,因此,lambda表示式中同樣也不能有同名的區域性變數。在一個lambda表示式中使用this關鍵字時,是指建立這個lambda表示式的方法的this引數。
使用lambda表示式的重點是延遲執行。畢竟,如果想要立即執行程式碼,完全可以直接執行,而無需把它包裝在一個lambda表示式中。之所以希望以後再執行程式碼,這有很多原因:
- 在一個單獨的執行緒中執行程式碼
- 多次執行程式碼
- 在演算法的適當位置執行程式碼
- 發生某種情況時執行程式碼
- 在必要時才執行程式碼
內部類是定義在另一個類中的類。使用內部類的原因是:
- 內部類方法可以訪問該類定義所在的作用域中的資料,包括私有的資料
- 內部類可以對同一個包中的其他類隱藏起來。
- 當想要定義一個回撥函式且不想編寫大量程式碼時,使用匿名內部類比較便捷。
靜態內部類,這種內部類只是為了把一個類隱藏在另外一個類的內部,並不需要內部類引用外圍類物件。為此,可以將內部類宣告為static,以便取消產生的引用。
代理
利用代理可以在執行時建立一個實現了一組給定介面的新類。這種功能只有在編譯時無法確定需要實現哪個介面時才有必要使用。
代理類可以在執行時建立全新的類。這樣的代理類能夠實現指定的介面。尤其是,它具有下列方法:
- 指定介面所需要的全部方法
- Object類中的全部方法
然而,不能再執行時定義這些方法的新程式碼,而是要提供一個呼叫處理器。呼叫處理器是實現了InvocationHandler介面的類物件。在這個介面中只有一個方法:invoke。
無論何時呼叫代理物件的方法,呼叫處理器的invoke方法都會被呼叫,並向其傳遞Method物件和原始的呼叫引數。呼叫處理器必須給出處理帶哦用的方法。
建立一個代理物件,需要使用Proxy類的newProxyInstance方法。這個方法有三個引數:
- 一個類載入器。作為Java安全模型的一部分,對於系統類和從因特網上下載下來的類,可以使用不同的類載入器。
- 一個Class物件陣列,每個元素都是需要實現的介面。
- 一個呼叫處理器
使用代理可能處於很多原因,例如:
- 路由對遠端伺服器的方法呼叫
- 在程式執行期間,將使用者介面事件與動作關聯起來
- 為除錯,跟蹤方法呼叫
代理類是在程式執行過程中建立的。一旦被建立,就變成了常規類,與虛擬機器中的任何其他類沒有什麼區別。
所有的代理類都擴充套件於Proxy類。一個代理類只有一個例項域--呼叫處理器,它定義在Proxy的超類中。為了履行代理物件的職責,所需要的任何附加資料都必須儲存在呼叫處理器中。
所有代理類都覆蓋了Object類中的toString、equals和hashCode。如同所有的代理方法一樣,這些方法僅僅呼叫了呼叫處理器的invoke。Object類中的其他方法沒有被重新定義。
對於特定的類載入器和預設的一組介面來說,只能有一個代理類。也就是說,如果使用同一個類載入器和介面陣列呼叫兩次newProxyInstance方法的話,那麼久只能夠得到同一個類的兩個物件,也可以利用getProxyClass方法獲得這個類。
代理類一定是public和final。如果代理類實現的所有介面都是public,代理類就不屬於某個特定的報。否則,所有非公有的介面都必須屬於同一個包。
可以通過呼叫Proxy類中的isProxyClass方法檢測一個特定的Class物件是否代表一個代理類。