18、Beanutils工具包
把Beanutils的jar包添加到Buildpath
如果在Beanutils工具包中使用到了別的工具包,在使用Beanutils工具包時,要把其使用的別的工具包也一起添加到Buildpath
19、 瞭解註解及java提供的幾個基本註解
@Deprecated
@Override
@SuppressWarnings
@Retention(RetentionPolicy.RUNTIME)保留註解到運行狀態
總結:註解相當於一種標記,加了註解就等於打上了某種標記,沒加,則等於沒有某種標記,以後,javac編譯器,
開發工具和其他程序可以用反射來了解你的類及各種元素上有無何種標記,看你有什麼標記,就去幹相應的事。
標記可以加在包,類,字段,方法的參數以及局部變量上。
20、 泛型
使用了通配符"?",就不能再使用與類型有關的方法
1. 定義泛型的方法
2. 定義泛型的類型
如果類的實例對象中多處都要用到同一個泛型參數,即這些地方引用的泛型類型都要保持同一個實際類型時,
這時候就要採用泛型的方式進行定義,也就是類級別的泛型,語法格式如下:
public class GenericDao<T>{
private T field1;
public void save(T obj){}
public T getById(int id){}
}
類級別的泛型是根據引用該類名時指定的類型信息來參數化類型變量的,如下兩種方式
GenericDao<String>dao=null;
new genericDao<String>();
注意:
在對泛型類型進行參數化時,類型參數的實例化必須是引用類型,不能是基本類型。
當一個變量被聲明爲泛型時,只能被實例變量和方法調用(還有內嵌類型),而不能被靜態變量和靜態方法調用。
因爲靜態成員是被所有參數化的類所共享的,所以靜態成員不應該有類級別的類型參數。
問題:類中只有一個方法需要使用泛型,是使用類級別的泛型,還是使用方法級別的泛型
<span style="font-size:18px;"> public class GenericDao<E>{
public void add(E x){
}
public E findById(int id){
}
public void delete(E obj){
}
public void delete(int id){
}
public void update(E obj){
}
public Set<E>findByConditions(String whete){
return null;
}
public Set<E> findByUserName(String name){
return null;
}
}</span>
21. 類加載器,就是加載類的工具Java虛擬機中有多個類加載器,系統默認三個主要類加載器,每個類負責加載特定位置的類
BootStrap, ExtClassLoader, AppClassLoader
類加載器也是Java類,因爲其他是Java類的類加載器本身也要被類加載器加載,顯然必須有
一個類加載器不是Java,這正是BootStrap。
Java虛擬機中的所有類加載器採用具有父子關係的樹狀結構進行組織,在實例化每個類裝載
器對象時,需要爲其指定一個父級類裝載器對象或者默認採用系統類裝載器爲其父級類加載。
22. 類加載器的委託機制
當Java虛擬機要加載一個類時,到底派出哪個類加載器去加載呢?
首先當前線程類加載器去加載線程中的第一個類。
如果類A中引用了類B,java虛擬機將使用加載類A的類裝載器來加載類B
還可以直接調用ClassLoader.loadClass()方法來指定某個類加載器去加載某個類。
23. 每個類加載器加載類時,又先委託給其上級類加載器
當所有祖宗類加載器沒有加載到類,回到發起者類加載器,還加載不了,則拋出ClassNoFoundException,
不是再去找發起者類加載器的兒子,因爲沒有getChild方法,即使有,那有多個兒子,找哪個呢?
對着類加載器的層次結構圖和委託加載原理,解釋先前將ClassLoaserTest輸出成jre/lib/ext目錄下的itcast.jar包
中後,運行結果爲ExtClassLoader的原因。
24. 編寫自己的類加載器
知識講解:
自定義類加載器的必須繼承ClassLoader
loadClass方法與findClass方法
defineClass方法
程序步驟:
編寫一個對文件內容進行簡單加密的程序。
編寫了一個自己的類加載器,可以實現對加密過的類進行裝載和解密
編寫一個程序調用類加載器加載類,在源程序中不能用該類名定義引用變量,因爲編譯器無法識別這個類,
程序中可以除了使用ClassLoader.load方法之外,還可以使用設置線程的上下文類加載器或者系統類加載器,然後再使用Class.forName。
實驗步驟:
對不帶包名的class文件進行加密,加密結果存放到另外一個目錄,例如: java MyClassLoader MyTest.class F:\itcast
運行加載類的程序,結果能夠被正常加載,但打印出來的類裝載器名稱爲AppClassLoader:java MyClassLoader MyTest F:\itcast
用加密後的類文件替換CLASSPATH環境下的類文件,再執行上一步操作就出問題了,錯誤說明是AppClassLoader類裝載器裝載失敗。
刪除CLASSPATH環境下的類文件,再執行上一步操作就沒問題了。
25. parametered 模板方法設計模式:
父類中定義好了子類統一的流程,父類中局部細節不能實現的地方,在子類中進行覆蓋描述,通過子類實現細節
父類-->loadClass/findClass(覆蓋該方法)/得到Class文件的轉換成字節碼-->definClass();
26. 有包名的類不能調用沒有包名的類
27. 一個類加載器的高級問題分析
編寫一個能打印出自己的類加載器名稱和當前類加載器的父子結構關係鏈的MyServlet,正常發佈後,看到打印結果爲WebAppClassloader。
把MyServlet.class文件打jar包,放到ext目錄中,重啓tomcat,發現找不到HttpServlet的錯誤。
把servlet.jar也放到ext目錄中,問題解決了,打印的結果是ExtclassLoader 。
父級類加載器加載的類無法引用只能被子級類加載器加載的類
28. 代理的概念與作用
程序中的代理
要爲已存在的多個具有相同接口的目標類的各個方法增加一些系統功能,
例如,異常處理、日誌、計算方法的運行時間、事務管理、等等,你準備如何做?
編寫一個與目標類具有相同接口的代理類,代理類的每個方法調用目標類的相同方法,
並在調用方法時加上系統功能的代碼。 (參看下頁的原理圖)
如果採用工廠模式和配置文件的方式進行管理,則不需要修改客戶端程序,在配置文件中配置是使用目標類、
還是代理類,這樣以後很容易切換,譬如,想要日誌功能時就配置代理類,否則配置目標類,
這樣,增加系統功能很容易,以後運行一段時間後,又想去掉系統功能也很容易
29. AOP :交叉業務的編程問題即爲面向方面的編程(Aspect oriented program ,簡稱AOP),
系統中存在交叉業務,一個交叉業務就是要切入到系統中的一個方面,如下所示:
安全 事務 日誌
StudentService ------|----------|------------|-------------
CourseService ------|----------|------------|-------------
MiscService ------|----------|------------|-------------
用具體的程序代碼描述交叉業務:
method1 method2 method3
{ { {
------------------------------------------------------切面
.... .... ......
------------------------------------------------------切面
} } }
交叉業務的編程問題即爲面向方面的編程(Aspect oriented program ,簡稱AOP),
AOP的目標就是要使交叉業務模塊化。可以採用將切面代碼移動到原始方法的周圍,
這與直接在方法中編寫切面代碼的運行效果是一樣的,如下所示:
------------------------------------------------------切面
func1 func2 func3
{ { {
.... .... ......
} } }
------------------------------------------------------切面
使用代理技術正好可以解決這種問題,代理是實現AOP功能的核心和關鍵技術。
30. 動態代理技術
要爲系統中的各種接口的類增加代理功能,那將需要太多的代理類,全部採用靜態代理方式,將是一件非常麻煩的事情!
寫成百上千個代理類,是不是太累!
JVM可以在運行期動態生成出類的字節碼,這種動態生成的類往往被用作代理類,即動態代理類。
JVM生成的動態類必須實現一個或多個接口,所以,JVM生成的動態類只能用作具有相同接口的目標類的代理。
CGLIB庫可以動態生成一個類的子類,一個類的子類也可以用作該類的代理,
所以,如果要爲一個沒有實現接口的類生成動態代理類,那麼可以使用CGLIB庫。
代理類的各個方法中通常除了要調用目標的相應方法和對外返回目標返回的結果外,還可以在代理方法中的如下四個位置加上系統功能代碼:
1.在調用目標方法之前
2.在調用目標方法之後
3.在調用目標方法前後
4.在處理目標方法異常的catch塊中
31. 實現AOP功能的封裝與配置
工廠類BeanFactory負責創建目標類或代理類的實例對象,並通過配置文件實現切換。
其getBean方法根據參數字符串返回一個相應的實例對象,如果參數字符串在配置文件中對應的類名不是ProxyFactoryBean,
則直接返回該類的實例對象,否則,返回該類實例對象的getProxy方法返回的對象。
BeanFactory的構造方法接收代表配置文件的輸入流對象,配置文件格式如下:
#xxx=java.util.ArrayList
xxx=cn.itcast.ProxyFactoryBean
xxx.target=java.util.ArrayList
xxx.advice=cn.itcast.MyAdvice
ProxyFacotryBean充當封裝生成動態代理的工廠,需要爲工廠類提供哪些配置參數信息?
目標
通知
編寫客戶端應用:
編寫實現Advice接口的類和在配置文件中進行配置
調用BeanFactory獲取對象
32. 傳統線程機制的回顧
a.創建線程的兩種傳統方式
在Thread子類覆蓋的run方法中編寫運行代碼
涉及一個以往知識點:能否在run方法聲明上拋出InterruptedException異常,
以便省略run方法內部對Thread.sleep()語句的try…catch處理?
在傳遞給Thread對象的Runnable對象的run方法中編寫代碼
總結:查看Thread類的run()方法的源代碼,可以看到其實這兩種方式都是在調用Thread對象的run方法,
如果Thread類的run方法沒有被覆蓋,並且爲該Thread對象設置了一個Runnable對象,該run方法會調用Runnable對象的run方法。
問題:如果在Thread子類覆蓋的run方法中編寫了運行代碼,也爲Thread子類對象傳遞了一個Runnable對象,
那麼,線程運行時的執行代碼是子類的run方法的代碼?還是Runnable對象的run方法的代碼?//子類的
涉及到的一個以往知識點:匿名內部類對象的構造方法如何調用父類的非默認構造方法。
多線程機制會提高程序的運行效率嗎?爲什麼會有多線程下載呢?
b.定時器的應用
Timer類
TimerTask類
c.線程的同步互斥與通信
使用synchronized代碼塊及其原理
使用synchronized方法
分析靜態方法所使用的同步監視器對象是什麼?
wait與notify實現線程間的通信
33.多個線程訪問共享對象和數據的方式
如果每個線程執行的代碼相同,可以使用同一個Runnable對象,這個Runnable對象中有那個共享數據,例如,買票系統就可以這麼做。
如果每個線程執行的代碼不同,這時候需要用不同的Runnable對象,有如下兩種方式來實現這些Runnable對象之間的數據共享:
將共享數據封裝在另外一個對象中,然後將這個對象逐一傳遞給各個Runnable對象。
每個線程對共享數據的操作方法也分配到那個對象身上去完成,這樣容易實現針對該數據進行的各個操作的互斥和通信。
將這些Runnable對象作爲某一個類中的內部類,共享數據作爲這個外部類中的成員變量,
每個線程對共享數據的操作方法也分配給外部類,以便實現對共享數據進行的各個操作的互斥和通信,
作爲內部類的各個Runnable對象調用外部類的這些方法。
上面兩種方式的組合:將共享數據封裝在另外一個對象中,每個線程對共享數據的操作方法也分配到那個對象身上去完成,
對象作爲這個外部類中的成員變量或方法中的局部變量,每個線程的Runnable對象作爲外部類中的成員內部類或局部內部類。
總之,要同步互斥的幾段代碼最好是分別放在幾個獨立的方法中,這些方法再放在同一個類中,這樣比較容易實現它們之間的同步互斥和通信。
極端且簡單的方式,即在任意一個類中定義一個static的變量,這將被所有線程共享。
34.線程池
線程池的概念與Executors類的應用
創建固定大小的線程池
創建緩存線程池//線程數可隨需求變化
創建單一線程池
關閉線程池
shutdown與shutdownNow的比較
用線程池啓動定時器
調用ScheduledExecutorService的schedule方法,返回的ScheduleFuture對象可以取消任務。
支持間隔重複任務的定時方式,不直接支持絕對定時方式,需要轉換成相對時間方式
35. Callable&Future
Future取得的結果類型和Callable返回的結果類型必須一致,這是通過泛型來實現的。
Callable要採用ExecutorSevice的submit方法提交,返回的future對象可以取消任務。
CompletionService用於提交一組Callable任務,其take方法返回已完成的一個Callable任務對應的Future對象。
36. Lock&Condition實現線程同步通信
Lock比傳統線程模型中的synchronized方式更加面向對象,與生活中的鎖類似,鎖本身也應該是一個對象。
兩個線程執行的代碼片段要實現同步互斥的效果,它們必須用同一個Lock對象。
讀寫鎖:分爲讀鎖和寫鎖,多個讀鎖不互斥,讀鎖與寫鎖互斥,寫鎖與寫鎖互斥,這是由jvm自己控制的,你只要上好相應的鎖即可。
如果你的代碼只讀數據,可以很多人同時讀,但不能同時寫,那就上讀鎖;
如果你的代碼修改數據,只能有一個人在寫,且不能同時讀取,那就上寫鎖。總之,讀的時候上讀鎖,寫的時候上寫鎖!
在等待 Condition 時,允許發生“虛假喚醒”,這通常作爲對基礎平臺語義的讓步。對於大多數應用程序,這帶來的實際影響很小,
因爲 Condition 應該總是在一個循環中被等待,並測試正被等待的狀態聲明。某個實現可以隨意移除可能的虛假喚醒,
但建議應用程序程序員總是假定這些虛假喚醒可能發生,因此總是在一個循環中等待。
一個鎖內部可以有多個Condition,即有多路等待和通知,可以參看jdk1.5提供的Lock與Condition實現的可阻塞隊列的應用案例,
從中除了要體味算法,還要體味面向對象的封裝。在傳統的線程機制中一個監視器對象上只能有一路等待和通知,
要想實現多路等待和通知,必須嵌套使用多個同步監視器對象。(如果只用一個Condition,兩個放的都在等,一旦一個放的進去了,
那麼它通知可能會導致另一個放接着往下走。)
---------------------- android培訓 、 java培訓 、 期待與您交流! ---------------------- 詳細請查看:www.itheima.com