n 內部類:定義在一個類內部的類,就稱爲內部類java
u 內部類分爲3種mysql
² 成員內部類:至關於成員變量程序員
² 局部內部類:定義在方法內部的,至關於局部變量(極少用到,瞭解便可)面試
² 匿名內部類:(經常使用)算法
Iterator it = new Iterator() {//直接定義類,並同時建立該類對象sql @Override數據庫 publicboolean hasNext() {編程 returnfalse;數組 }安全 @Override public Object next() { returnnull; } @Override publicvoid remove() {
} }; |
u 使用要點:
² 內部類的構造方法不能夠在其餘類裏直接調用!
² 內部類若是有靜態成員變量,那麼內部類也必須是靜態的!
² 非靜態內部類Car.Engine en = new Car().new Engine();
或者能夠這樣寫:
Car c = new Car();
Car.Engine en = c.new Engine();
² 靜態內部類 Car.Engine en = new Car.Engine();
² 外部類在使用內部類的時候,能夠直接實例化 Engine en = new Engine();
n 抽象類: 使用abstract關鍵字修飾的類,稱之爲抽象類
u 使用要點:
² 有抽象方法的類只能定義成抽象類(要使用abstract修飾)
² 抽象類不能實例化,不能生成對象
² 能夠定義構造方法但不能夠調用
² 抽象類只能被繼承
² 繼承抽象類的子類必須實現抽象類的抽象方法
u 抽象類的意義:
² 使一個類更加具備模板意義,強制規定了子類的行爲
² 把設計工做和具體的代碼實現工做作了分離
n 接口: 類的模板,用來作設計或規範,比抽象類更抽象
u 飛機、籃球、子彈、石頭,這些事物之間有什麼共同點?是否能用繼承體現他們的關係?
n 這些事物之間沒有特別明顯的共同屬性,也很難抽象出父類(很難概括爲一個類別),可是它們都具備一些相同的行爲能力:那就是飛行
u 所以這裏咱們再也不使用抽象類,而使用接口來體現它們的關係,抽象出它們的共同行爲
publicinterface Flyable{ //接口中的方法都是抽象的,沒有實現 publicabstractvoid fly(); }
class Plane implements/*實現*/ Flyable { @Override publicvoid fly() {
} }
class Stone implements Flyable { @Override publicvoid fly() {
} }
class Bullet implements Flyable{ @Override publicvoid fly() {
} }
|
n 接口的特色:
u 接口中的方法所有都是抽象的,不能有方法實現代碼!
² 接口中的方法,默承認以省略public 和 abstract關鍵字,系統會自動加上
u 對於實現了接口的類,必須實現接口中的全部抽象方法。
u 接口中的屬性,所有都是靜態常量。
² 默承認以省略final關鍵字,系統會自動加上
u 接口是能夠多繼承的!好比接口A能夠同時繼承接口B和接口C
n 經常使用類:
u 基本數據類型的包裝類
u byteàByte、booleanà Boolean、char à Character、
shortà Short、intà Integer、longà Long、
floatà Float、doubleà Double
n String類和StringBuffer類
u 掌握String類和StringBuffer的區別
u StringBuffer是帶緩衝的可變長度字符串,若是一個字符串在內存中頻繁的被修改,爲了可以提升性能,這時咱們就會考慮使用StringBuffer來存儲字符串內容。
u StringBuffer類同時也給咱們提供了不少實用處理字符串的方法
//計算字符串長度 publicsynchronizedint length() //把字符串兩邊空格去掉再計算長度 publicsynchronizedvoid trimToSize() //得到指定下標位置上的一個字符 publicsynchronizedchar charAt(int index) //設置指定下標位置上的字符,將字符內容更改成ch的值 publicsynchronizedvoid setCharAt(int index, char ch) //向字符串末尾追加內容 publicsynchronized StringBuffer append(String str) //截取字符串的一部分,從指定下標開始,到指定下標結束 publicsynchronized String substring(int start, int end) //計算指定內容在整個字符串中出現的下標位置 publicint indexOf(String str) //反轉逆序整個字符串 publicsynchronized StringBuffer reverse() ...... |
u
//計算a的絕對值 publicstaticint abs(int a) publicstaticint abs(float a) ...... //計算a和b的最大值 publicstaticint max(int a, int b) publicstaticint max(double a, double b) ...... //計算a和b的最小值 publicstaticint min(int a, int b) //生產一個0至1的隨機小數 publicstaticdouble random() ...... |
Math類
u System類
字段摘要 |
|
static PrintStream |
err 「標準」錯誤輸出流。 |
static InputStream |
in 「標準」輸入流。 |
static PrintStream |
out 「標準」輸出流。 |
方法摘要 |
|
static long |
currentTimeMillis() |
static void |
exit(int status) |
static void |
gc() |
static String |
|
static int |
identityHashCode(Object x) |
static long |
nanoTime() |
n 集合類: 一組數據的集合,相似於數組,功能比數組強大
u 集合的特色
² 集合的長度是可變的
² 集合中存儲的元素都是對象
² 全部的List集合類都實現了一個叫作Collection的接口
u List集合類的結構圖:
u 掌握接口List和Set集合有什麼不一樣
² List接口和Set接口都繼承了Collection接口
² 接口定義了不一樣集合類的做用以及存儲數據的方式
² 其中Set全部集合中的數據對象都是沒有順序且不可重複的
² 其中Vector集合是線程安全的
u 掌握ArrayList和LinkedList的區別
² ArrayList是簡單的順序結構,而LinkedList是鏈表結構,兩者各有優缺點。順序結構因爲有下標的存在訪問元素時速度比較快!但插入或刪除元素會使得整個集合的元素都須要挪動,因此插入刪除效率比較低!
² 鏈表結構因爲採用了指針(也叫引用)連接對象,例如:
a對象保存了一個b對象的引用,b對象保存了一個c對象的引用,這時對象a、b、c就構成了一個鏈表結構
a |
b |
c |
a |
b |
c |
d |
當插入元素d時,不須要挪動元素,而只須要修改指針(引用)便可
所以鏈表結構在作插入刪除操做時,速度較快,但因爲沒有下標,訪問元素時,必須從第一個元素開始,挨個查找下一個元素,因此效率是比較低的!
結論:ArrayList訪問效率高,插入刪除效率低
LinkedList訪問效率低,插入刪除效率高
u 掌握Collection和Collections有什麼不一樣
Collection是一個接口,規定了全部集合的方法,至關於全部集合的一個總規範
Collections是一個類,裏面提供了各類操做集合的工具方法
u Collections類的sort方法
要求集合中全部元素對象都必須實現了Comparable接口
u Collection的父接口Iterable
這個接口規定了全部實現Collection接口的集合,都必需要有一個itrerator()方法,這個方法返回一個Iterator(迭代器)類型的對象
u Map集合類
u
key |
value |
key
|
value
|
key
|
value
|
Map集合的特色
² 以Entry(鍵值對)的方式來存儲對象
² Map集合的結構
² 沒有順序
key
|
value
|
u HashMap和HashTable區別
² HashMap和HashTable都實現了Map接口,但不一樣的是,HashTable是一個線程安全的Collection
² HashMap容許將null做爲一個entry(鍵值對)的key或者value,而Hashtable不容許null。
u 泛型: 類型檢查,防止出現類型轉換錯誤,而且減小了手動類型轉換的次數
ArrayList<Int> list = new ArrayList<Int>(); list.add(new Int(45)); list.add(new Int(99)); list.add(new Int(22)); Collections.<Int>sort(list);
Collections.<Int>sort(list, new Comparator<Object>() { @Override publicint compare(Object o1, Object o2) { return 0; } });
print(list);
privatevoid print(Collection<? extends Object> list) { for(Object o : list) {
} }
class Int implements Comparable<Object>{ intvalue; public Int(int value) { this.value = value; }
@Override publicint compareTo(Object o) { if(o instanceof Int) { Int i = (Int)o; if(this.value > i.value) { return 10; } elseif(this.value == i.value) { return 0; } } return -10; }
public String toString() { returnthis.value+""; } } |
聲明類型 |
聲明類型 |
u HashMap的深度解析
² 在使用集合時,JAVA規範中要求,凡是要存入集合中的元素,都要重寫對象的equals方法,請問這是爲何?(面試題)
key-value
|
key-value
|
key-value
|
key-value
|
key-value |
在解答整個問題以前,要先了解HashMap 的存儲結構
第1、查看源碼咱們能夠得知HashMap本質仍然是一個數組
第2、在使用put方法存放每個Entry(鍵值對)的時候,HashMap會根據key(鍵)的hashcode值進行計算,得出一個下標,而後將其存放到相應的數組位置上。
關於hashcode()方法,因爲是一個本地方法,因此咱們沒法知道它是如何實現的,但無論怎樣,至少咱們知道,key-value的存放位置是跟key 的hashcode值有關。
那麼當兩個key的hashcode值同樣時,鍵值對又該如何存放呢?
咱們再查看一下源代碼,會發如今HashMap當中有一個內部類Entry
對於每個Entry,實際上它自己是一個鏈表結構的,它的next屬性保存另一個對象的引用。JAVA爲何要這樣設計呢?
原來,在存放Entry 的時候,當一個Entry的key的hash碼相同,則在數組的同一個位置上,則會以鏈表的形式存儲
key-value |
key-value
|
key-value
|
key-value
|
key-value
|
key-value
|
當key的hash碼同樣時,會存放到數組的 同一位置,並以鏈表形式存儲
key-value
|
在獲取元素的時候,HashMap一樣會去計算傳入key的hash碼,首先定位到數組的位置上,而後利用傳入key的equals方法來比較鏈表上的每個key,比較結果相同時,纔會將value值取出來。
若是沒有重寫equals方法,那會形成什麼嚴重後果呢?
每一個對象都有本身的hashcode值,經過hashcode()方法得到,因爲沒有重寫equls方法,定位到數組的位置後,key的比較沒法相等,所以就沒法把數據取出來!
從這裏咱們也能夠看出,當使用HashMap存儲數據時,爲了可以進一步的提升HashMap的效率,咱們但願數組的每個位置上元素都不要重複,不然每次獲取元素時,都要對鏈表上的每個key進行equals比較,而鏈表的訪問效率是比較低的,因此鏈表的長度越小越好。
這也就提出了一個新的問題?如何才能使得元素在數組上存放的時候,位置不衝突?說白了,怎麼能把這些元素分的越散越好?這就要從新去考慮咱們的散列算法(hash算法)。
關於HashMap 更多的信息,因爲篇幅有限再也不作更多介紹,有興趣自行百度。
u 迭代器
next() |
next() |
def
|
abc |
一個帶遊標的數組
next()方法會返回遊標的下一個元素「abc」同時 遊標會向後移動一個位置
遊標 |
再次調用next()方法返回「def」
hasNext()返回是否還有下一個元素可訪問
迭代器中的remove方法刪除迭代器剛剛返回的 元素,而且不能同時調用兩次!
使用迭代器進行for循環
for(Iterator it = list.iterator(); it.hasNext();) { Student stu = (Student)it.next();
} 固然也能夠加上泛型,省去類型轉換的麻煩 for(Iterator<Student> it = list.iterator(); it.hasNext();) { Student stu = it.next();
}
|
n 異常處理: java中提供了一種處理程序錯誤的機制,叫作異常處理
u 考慮這樣一個問題,當咱們打算寫這樣一個程序,將D:/a.txt 複製到E:/a.txt
if(D:/a.txt這個文件存在) { if(E盤剩餘空間足夠複製a.txt文件) { if(文件讀取一半時出現錯誤,好比a.txt被修改或刪除了) { 中止複製工做,提示覆制失敗 } else { if(若是E:/a.txt文件不存在) { 在E盤下新建a.txt文件 } copy("D:/a.txt","E:/a.txt");//執行復制動做 } } else { 提示E盤剩餘空間不足 } } else { 提示a.txt文件不存在 }
|
咱們的代碼會這樣寫:
能夠看到,咱們真正複製文件的代碼只有黑色字體部分的少許代碼
而大部分代碼邏輯在作條件判斷,目的就是爲了程序出錯時,
能夠作出一些相應的處理,並能給出一些錯誤的提示信息
程序員在寫代碼的時候,要考慮的錯誤處理比功能處理還要多,這顯然有些本末倒置了,爲了可以在寫程序時,考慮問題更專一於程序的功能,而不是錯誤處理,所以JAVA設計出了異常處理機制。
因此,利用異常處理機制咱們能夠把程序修改爲下面的樣子:
try { if(若是E:/a.txt文件不存在) { 在E盤下新建a.txt文件 } copy("D:/a.txt","E:/a.txt");//執行復制動做
} catch (發現文件不存在) { 提示a.txt文件不存在 } catch (發現E盤剩餘空間不夠) { 提示E盤剩餘空間不足 } catch (文件複製一半時出現錯誤) { 中止複製工做,提示覆制失敗 } |
這裏指明出現了什麼樣的異常情況 |
JAVA容許咱們以這種方法來判斷異常的發生 這樣咱們就能夠把全部的異常情況集中起來作處理了!
|
在這裏程序員能夠專一於文件複製功能的實現,而暫時先不去關心錯誤如何處理
|
u Exception類的繼承結構
Throwable |
Error |
Exception
|
RuntimeExcepton
|
RuntimeException,叫作運行時異常,因爲這種異常編譯階段一般難以檢查出來,這類異常也稱爲不檢查異常(unchecked)編譯器不會強制要求程序人員作try-catch的異常處理 例如: //下標越界異常 //空指針異常 //類型轉換異常 //算術異常 |
若干子類...... |
除運行時異常之外的其它異常類,在編譯期間會檢查出來的異常,咱們稱之爲檢查異常,對於這類異常,在程序員寫代碼的時候,若是使用了有可能產生這類異常的方法,則編譯器會強制要求程序人員必須try-catch處理異常 例如: //類找不到異常 //IO流使用異常 //數據庫交互異常 //算術異常 |
其它子類...... |
對於ERROR這個類咱們沒必要太關心,由於ERROR表明了非程序代碼的錯誤,例如虛擬機內存不足而致使的程序終止,程序員不須要對這類錯誤作任何處理。
在JAVA的世界中,一切都是對象,因此毫無例外的,異常的產生也是以對象的形式存在,例如當發生數組下標越界的異常時,程序會自動生成一個IndexOutOfBoundsException類的實例對象, 並把這個對象以 throw的形式拋出!
在任何的程序設計語言中,都會有意外錯誤的狀況發生,在一個小的程序中,能夠用比較簡單的方法處理異常,可是在一個大的系統中,每個方法都要有處理異常情況的代碼,這樣必然使得程序變得很是複雜和龐大。因此,JAVA才設計出了這樣的辦法:
當一個方法內出現錯誤時,錯誤不在方法內作處理,而是發出一個錯誤信息,把它傳給調用的人,例如:方法1()----> 方法2()----> 方法3()
若是方法3()裏出現了任何錯誤,因爲方法3的邏輯代碼已經很是複雜,所以方法3不想對任何錯誤作處理,那麼它發出一條消息給調用它的方法2,假設方法2也比較複雜,爲了減小本身的工做量,它也能夠不作處理,而把這個錯誤消息再一次發送給調用它的方法1,若是方法1仍然不作處理繼續把消息向上發送,最終就由虛擬機來接管了。
虛擬機是全部代碼的執行者,所以它處理錯誤的方式比較粗暴!把錯誤的消息打印出來以後,就直接把程序終止了。
固然若是不想讓某個錯誤影響到整個系統的運行,在方法內應該攔截這個錯誤消息,而且能夠作出相應的錯誤處理。
固然,若是你犯懶的話,攔截了消息,不作處理也是能夠的。例如:
try{ inta = 3/0; } catch (Exception e) { //不作任何處理 } //不影響下面代碼執行 ...... ......
|
在JAVA中,錯誤消息都是以對象的形式自動向上級拋出的,固然你也能夠定義本身的消息類型,手動拋出去。在JAVA中這種錯誤消息咱們稱之爲「異常」,若是一個異常在被拋出時沒有任何捕獲的動做,拋給上級後,上級也不作處理,最終就會拋給虛擬機,虛擬機不論錯誤的大小,一概都會打印錯誤信息並終止程序。
n 數據庫複習(MySQL)
u 視圖
² 建立一個虛擬表,虛擬表的數據由指定的select語句查詢而得。
² 因爲該表實際中沒有數據,只是一個概念表,因此稱之爲視圖
² 視圖能夠大大的簡化查詢語句,使得sql語句變得相對簡單,例如在分佈式系統中,程序的執行效率每每還會受到服務器之間的網速的影響。
所以,減小服務器之間通訊時的數據包大小,就變得尤其重要了。
服務器 |
遠程數據庫 |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX巨複雜的sql語句 |
發送到數據庫時間: 0.04秒 |
使用視圖以後
遠程數據庫 |
服務器 |
select * from view_a |
發送到數據庫時間: 0.01秒 |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX 事先在數據庫裏定義好的視圖 |
這種好處,只有大數據量,高併發時,纔會體現的出來
它跟存儲過程有着一樣的好處。
u 存儲過程
² 它讓咱們以編程的方式來定義一系列SQL語句
² 在存儲過程中,咱們能夠定義變量,運算。能夠接受參數,能夠返回結果,與自定義函數相似
² 而它的執行效率要高於使用JDBC操做數據庫,因此不少時候,若是程序對操做數據庫的執行速度要求很高的話,就應該儘可能多的使用存儲過程來代替大量的JDBC代碼。
l 練習:使用存儲過程作分頁查詢
u 索引
² select * from student where city = 'beijing' and age = ......
u 事務
² 事務的隔離級別:
l Read Uncommitted(讀取未提交內容)髒讀
l Read Committed(讀取提交內容)
l Repeatable Read(可重讀)
可重複讀隔離級別是最嚴格的隔離級別。在該隔離級別下,一個事務的影響徹底與其餘併發事務隔離,髒讀、不可重複的讀、幻像讀現象都不會發生。當使用可重複讀隔離級別時,在事務執行期間會鎖定該事務以任何方式引用的全部行。所以,若是在同一個事務中發出同一個SELECT語句兩次或更屢次,那麼產生的結果數據集老是相同的。所以,使用可重複讀隔離級別的事務能夠屢次檢索同一行集,並對它們執行任意操做,直到提交或回滾操做終止該事務。可是,在事務存在期間,不容許其餘事務的執行影響到這個事務正在訪問的任何行。爲了確保這種行爲不會發生,鎖定該事務所引用的每一行-- 而不是僅鎖定被實際檢索或修改的那些行。所以,若是一個事務掃描了1000行,但只檢索10行,那麼它所掃描的1000行(而不只是被檢索的10行)都會被鎖定。
l Serializable(可串行化)
u mysql 的存儲引擎
² MyIsam 查詢效率比較高,但不支持事務
² InnoDB 支持事務,查詢效率略低,默認以聚簇索引方式存儲
nJDBC(Java Data Base Connectivity)
u JDBC是一種技術規範,定義了鏈接數據庫的方式。
Oracle |
JAVA |
Mysql |
SQLServer |
JAVA鏈接不一樣的數據庫,方法確定是不同的,每一個數據庫都提供了本身特有的函數方法,所以須要使用不一樣的JAVA-API來實現鏈接數據庫。
例如鏈接Mysql的方法叫 connectMysql() 鏈接Oracle的方法叫connectOracle()
可是,這樣作的話須要程序員去記住每一種方法的原理和特色以及使用方式。顯然很是的麻煩
爲了能讓鏈接數據庫變的更簡單,JAVA定義了一個規範,規範中聲明:
JAVA自己不提供任何鏈接數據庫的代碼,全部數據庫企業本身來提供一套鏈接本身數據庫的JAVA代碼。可是!這套JAVA代碼必需要遵循必定的規範,例如:全部的類都應該叫什麼名字,每一個類應該有什麼方法。當全部的API都遵循了這個規範,達到了統一。程序人員在使用JAVA代碼鏈接不一樣的數據庫時,才能變得簡單和易用。
所以JAVA自己提供了這樣一套接口類和一些相關的輔助類,而沒有任何鏈接數據庫的代碼實現,實現類都由數據庫廠商本身來提供。
咱們把這些實現代碼也稱之爲驅動程序
這樣,當咱們再次使用JDBC鏈接數據庫時,就變得簡單多了
Oracle |
SQLServer |
JAVA |
Oracle提供的驅動程序 |
Mysql提供的驅動程序 |
SQLServer提供的驅動程序 |
JDBC接口 |
JAVA聲明的規範 |
Mysql |
調用同一個方法,使用不一樣的驅動,就能夠鏈接不一樣的數據庫,這樣用起來是否是感受爽多了呢? JDBC就像是一個萬能轉換器同樣,幫咱們把不一樣的實現代碼屏蔽掉了,咱們只須要了解一個使用接口就能夠了,這裏再一次體現出了封裝的思想!
u JDBC編程的步驟:
² 加載驅動 xxx.jar
² 實例化驅動類並註冊給DriverMananger
Driver d = new com.mysql.jdbc.Driver(); DriverManager.registerDriver(d); |
² 自動註冊驅動對象,這是推薦的寫法
|
² 得到數據庫鏈接(三個參數:一、數據庫鏈接字符串 二、用戶名 三、密碼)
Connection conn = DriverManager.getConnection( "jdbc:mysql://localhost:3306/test", "root", "root"); |
² 建立執行語句對象
Statement stmt = conn.createStatement(); |
² 執行SQL語句得到結果集對象
ResultSet rs = stmt.executeQuery("select * from student"); |
² 遍歷並展現結果集
while(rs.next()) {
} |
² 關閉全部數據庫鏈接資源
rs.close(); stmt.close(); conn.close(); |
u JDBC的異常處理
u 事務
conn.setAutoCommit(false); //關閉事務的自動提交 conn.commit();//手動提交 conn.rollback();//catch到異常時,事務進行回滾 |
u 批量處理
Statement stmt = null; stmt = conn.createStatement(); stmt.addBatch("insert into student values(null,'測試888',20)"); stmt.addBatch("update student set age = 199 where name = 'lisi'"); stmt.addBatch("update student set age = 204 where name = '測試52'"); int[] rscount = stmt.executeBatch(); for (int i = 0; i < rscount.length; i++) {
} stmt.close(); conn.close();
|
u PreparedStatement
預編譯所帶來的好處是巨大的,它不只提升了SQL語句的執行效率,還有效的防止了SQL注入
u JDBC調用存儲過程
n 文件IO流java提供的一套讀寫文件的API
u 首先認識一下File類
² 這個類位於java.io包中
² 它是一個文件和目錄路徑名的抽象表示形式。
² 將文件讀取到內存當中,或者在指定目錄生成文件,都須要藉助File類
u 什麼是流?
數據源A |
數據源B
|
數據源(數據源能夠是一個文件,也能夠是內存裏的一個數據塊等)A傳輸數據到數據源B。須要在兩個數據源之間創建一個管道,如同流水通常,數據從數據源A經過管道流入數據源B。這個創建出來的管道,咱們稱之爲流。數據從一個地方流向另外一個地方的時候,都須要用到流
u 從流的功能來劃分:節點流 和 處理流
u 從流的方向上來劃分:輸入流 和 輸出流
u 從流讀取數據的大小上來劃分:字節流 和 字符流
u 四大抽象類:InputStream(字節輸入流)、OutputStream(字節輸出流)、Reader(字符輸入流)、Writer(字符輸出流)
² FileInputStream、FileOutputStream
² 讀寫文件的輸入和輸出字節流
² FileReader、FileWriter
² 讀寫文件的輸入和輸出字符流
² BufferedInputStream、BufferedOutputStream
² 帶緩衝的字符輸入、輸出流,是普通字節流的一種包裝流,將它套接在普通字節流之上來使用。例如:
FileInputStream fis=newFileInputStream();
BufferedInputStream bis = newBufferedInputStream(fis);
fis字節輸入流 |
帶緩衝的字節輸入流 |
² BufferedReader、BufferedWriter
² 帶緩衝的字符流同理
² DataInputStream、DataOutputStream
² 數據處理流,容許以平臺無關的方式將基本數據類型寫入到磁盤中。
² ObjectInputStream、ObjectOutputStream
² 對象流可以將對象直接存儲到磁盤中
² 對象的存儲也稱之爲對象的序列化(串行化)要想實現對象的序列化,該對象的類必須實現Serializable接口
n 反射機制(重點!)
execute("System.out.println('sdfasdf')");
java全部的代碼都是編譯好以後才能執行的。沒有動態執行語句的功能,所以它還稱不上是一種動態語言。爲了彌補這一缺陷,JAVA設計了反射這一律念
利用反射機制,JAVA在運行期間能夠加載一個編譯期間未知的class,獲取它的構造,生成對象,給屬性設值、調用其方法。而不須要將代碼寫死。
更直白的說: 即便我不知道類的名字,也能夠動態加載這個類,並生成這個類的對象,並調用它的方法,而在個人代碼當中並不會出現以下的語句:
Student stu = new Student();
stu.study();
所以至關於我作到了動態的執行代碼的效果!
n 動態代理(重點!)
它的重要性沒法形容,應用之廣也是咱們不能想象的
它從根本上解決了面向切面編程的難點。讓咱們能夠攔截任意的方法
這裏介紹的是JDK動態代理,它要求委託對象的類必須實現接口
除此之外還有Cglib的動態代理,是不須要實現接口的
代理對象proxy 方法a () 方法b (args...) 方法c (args...)
自定義的處理器 Handler |
委託對象atm 方法a () 方法b (args...) 方法c (args...)
|
MyHandler //利用反射機制執行請求的方法 invoke(proxy,method,args)
ATM atm |
JDK的動態代理要求委託對象的類必須實現一個接口,在生成代理對象時,會利用該接口來動態生成一個代理對象,它與委託對象有着如出一轍的方法,同時須要咱們自定義一個執行處理器(InvocationHandler)
在代理對象接收到方法調用的請求時,會執行處理器的invoke方法,這樣的話,咱們只要在處理器invoke方法先後加上本身想要的代碼,就能夠作到方法的攔截了。
瞭解更多詳情請登陸超人學院網站http://www.crxy.cn或者每週日晚八點半相約免費公開課 https://ke.qq.com/course/53102#term_id=100145289 具體詳情請聯繫QQ2435014406