Java反射
加載類概述
類加載分為三個(gè)階段:類加載、連接和初始化
加載:是指將class文件讀取到內(nèi)存中,以便為該文件創(chuàng)建Class對象。
任何類被使用系統(tǒng)都會創(chuàng)建一個(gè)Class對象連接:驗(yàn)證class文件知否符合要求。準(zhǔn)備,為靜態(tài)成員分配內(nèi)存。解析class文件
初始化:進(jìn)行構(gòu)造方法的初始化
類加載的時(shí)機(jī):
創(chuàng)建類的實(shí)例對象
調(diào)用類的靜態(tài)成員,為靜態(tài)變量賦值
調(diào)用類的靜態(tài)方法。
使用反射生成相應(yīng)的Class對象
初始化某個(gè)類的子類
直接運(yùn)行主類
類加載器的分類
根類加載器
BootstrapClassLoader
負(fù)責(zé)一些核心類的加載,比如String int float System
這些類頻繁的與內(nèi)存進(jìn)行交互,一般是非常快,是偽類,用c c++寫
擴(kuò)展類加載器
Extension ClassLoader 在ext包下的jar都會該加載器
應(yīng)用類加載器
App ClassLoader 平常我們自定義的類都是用的應(yīng)用類的加載器
反射概述
反射就是獲得某個(gè)類在運(yùn)行狀態(tài)中的字節(jié)碼對象,Class對象,并根據(jù)該對象中的方法,去解析該類中的屬性和方法。并且去調(diào)用該類的屬性和方法。
這種動態(tài)獲取信息,并且動態(tài)調(diào)用對象的方法就是java語言的反射機(jī)制
獲取Class對象
類名.class
new 類名().getClass()
Class,forName(“類的全路徑”)
反射的使用
基本用法
通過反射獲取無參的構(gòu)造方法和獲取帶參的構(gòu)造方法并使用
public static void main(String[] args) throws Exception{
Class<People> clazz = Peo;
//獲得該Class對象所表示的類的無參的構(gòu)造方法,并為其創(chuàng)建一個(gè)實(shí)例.
//不是無參的構(gòu)造,就不能用這種方式
People people = clazz.newInstance();
String b = ;
Sy(b);
//獲取該Class對象所表示的類的有參的構(gòu)造方法,參數(shù)寫相對應(yīng)參數(shù)類型的Class對象,不寫默認(rèn)為空,返回?zé)o參構(gòu)造方法
constructor<People> constructor = clazz.getConstructor);
People people = con();
String b = ;
Sy(b);
}
通過反射獲取公共的成員變量和獲取私有的成員變量
public static void main(String[] args) throws Exception {
//先通過反射獲取實(shí)例
Class<People> clazz = Peo;
People people = clazz.newInstance();
//獲取該Class對象表示的類的公共的成員變量
Field b = clazz.getField("b");
String o = (String(people);
Sy(o);
//獲取Class對象表示的類的私有的成員變量
//通過暴力反射
Field a = clazz.getDeclaredField("a");
//暴力反射要先設(shè)置權(quán)限
a.setAccessible(true);
int o1 = (in(people);
Sy(o1);
}
通過反射獲取公共的成員方法
Class對象中的getMethod() 方法,獲取該方法,返回Method對象
Method對象中的invoke() 方法,執(zhí)行該方法
這是在運(yùn)行期間,通過反射獲取字節(jié)碼對象,并且運(yùn)行方法的方式
public static void main(String[] args) throws Exception {
Class<People> clazz = Peo;
Constructor<People> constructor = clazz.getConstructor);
People people = con("dsa");
//獲取獲取該Class對象表示的類的公共的成員方法
Method m = clazz.getMethod("text");
Object invoke = m.invoke(people);
Sy(invoke);
}
通過反射越過泛型檢查
泛型只在編譯期間有效,在運(yùn)行期間無效
通過反射實(shí)現(xiàn)動態(tài)代理
代理,相當(dāng)于中介,自己要做的事情沒有做,交給了別人
動態(tài)代理:程序運(yùn)行的過程中產(chǎn)生的這個(gè)對象。
這個(gè)對象就是通過反射來獲得的一個(gè)實(shí)例對象(代理對象),
實(shí)現(xiàn)
通過java.lang.reflect 包下的Proxy對象 和 InvocationHandler接口生成代理對象,注意,只能代理接口。
更強(qiáng)大的代理:使用cglib
創(chuàng)建代理對象:
public static Object newProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler h)throws IllegalArgumentException
都會調(diào)用方法 InvocationHandler 接口中的 invoke() 方法
Object invoke(Object proxy,Method method,Object[] args)throws Throwable
代碼解析
public static void main(String[] args) {/*** 第一個(gè)參數(shù):告訴虛擬機(jī)通過反射創(chuàng)建出類的字節(jié)碼文件用哪個(gè)字節(jié)碼加載器(應(yīng)用類加載器)加載到內(nèi)存* 第二個(gè)參數(shù):告訴虛擬機(jī)通過反射創(chuàng)建出來的字節(jié)碼文件中應(yīng)該有多少個(gè)方法,也就是被代理對象實(shí)現(xiàn)了那些接口* 第三個(gè)參數(shù):告訴虛擬機(jī)創(chuàng)建的字節(jié)碼文件中的方法應(yīng)該怎么處理*/Icar o =(Icar) Proxy.newProxyInstance(), GooleCar.cla(), new InvocationHandler() {/**** @param proxy 動態(tài)代理的實(shí)例,不用管* @param method 動態(tài)代理對象正在執(zhí)行的方法* @param args 動態(tài)代理對象正在執(zhí)行的方法中的參數(shù)的值,不寫默認(rèn)為null* @return* @throws Throwable*/@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {String start = me();if("start".contentEquals(start)){/*** 執(zhí)行當(dāng)前的方法。* 第一個(gè)參數(shù):是被代理的對象* 第二個(gè)參數(shù):方法執(zhí)行的參數(shù)的值,不寫默認(rèn)為空*(new GooleCar(),args);Sy("hahahahahhah");}return null;}});o.start();}
動態(tài)代理解決亂碼問題
當(dāng)進(jìn)行二次開發(fā)的時(shí)候,我們只有api,沒有源碼,也不能繼承,要想增加功能,進(jìn)行二次開發(fā),使用動態(tài)代理模式
解決亂碼問題,使用過濾器。每次請求都進(jìn)行了中文亂碼問題的處理。
實(shí)現(xiàn):增請HttpServletrequest類中的getParameter()方法,使其獲取中文數(shù)據(jù)的時(shí)候,不出現(xiàn)亂碼問題
代碼實(shí)現(xiàn)
final HttpServletRequest request = (HttpServletRequest) servletRequest;
要使用final修飾才可以
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {final HttpServletRequest request = (HttpServletRequest) servletRequest;//在不知道源碼,不能繼承的情況下改變r(jià)equest中的getParameter方法,解決亂碼問題HttpServletRequest myRequest = (HttpServletReque(), reque().getInterfaces(), new InvocationHandler() {@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {Object obj = null;String name = me();if ("getParameter".equalsIgnoreCase(name)) {//增強(qiáng)getParameter()方法String method1 = reque();if ("get".equalsIgnoreCase(method1)) {//get請求解決亂碼問題,轉(zhuǎn)碼String invoke = (String) me(request, args);String a = new String("ISO-8859-1"), "utf-8");return a;} else { //post請求解決亂碼問題reque("utf-8");obj = me(request, args);}}else {obj = me(request,args);}return obj;}});(myRequest,servletResponse);}
注解
注解要求:
了解
開發(fā)中地位:類似dom4j解析XML文件. XML文件的解析程序員不會去解析,配置XML文件。 后期的開發(fā)中不會自定義注解,反射讀取注解信息.
什么是注解
注解就相當(dāng)于一個(gè)數(shù)據(jù)類型,與類、接口類似
注解的作用
配置文件
生成幫助文檔
編譯檢查
注解特點(diǎn)
直接可以在變量、方法、類之上加載
注解可以由屬性,也可以沒屬性
注解的作用范圍
源碼期間有效
String類上的 ,注釋里面的注解,幫助生成幫助文檔,可以識別String類上的相關(guān)的注解
@Author, 表示作者
@Since,表示版本
@See ,參照的東西
編譯期間有效
告訴編譯器部分信息
@Override 聲明當(dāng)前方法是重寫父類的方法
@Deprecated 聲明以下方法是過時(shí)的方法,不建議大家使用
@Suppresswarning 抑制編譯器發(fā)生警告信息
運(yùn)行期間有效
當(dāng)我們在當(dāng)前代碼上以Junit方式運(yùn)行時(shí),Junit會運(yùn)行方法上包含@Test注解的方法
@Test
我們再當(dāng)前代碼上以Junit方式運(yùn)行時(shí),Junit會運(yùn)行方法上包含@Test注解的方法
自定義注解
格式:
public @interface 注解名稱{public 屬性類型 屬性名稱1();public 屬性類型 屬性名稱2() default 默認(rèn)值;}
自定義注解屬性支持的類型:
基本數(shù)據(jù)類型(4類8種),String,Class,Annotation(注解類型),枚舉類型,
以及以上類型的一維數(shù)組類型
注解作用: 配置作用
配置:開發(fā)的時(shí)候部分信息不希望寫死在程序中,例如數(shù)據(jù)庫的用戶名和密碼,可以將用戶名和密碼存放在.txt , .properties ,
.xml文件中,利用程序來讀取文件中的內(nèi)容
框架:一大堆工具類組合,目的:加速項(xiàng)目開發(fā)
什么時(shí)候用注解來做配置?
如果配置信息不會發(fā)生的修改,例如servlet路徑,建議使用注解的形式
如果配置信息需要發(fā)生頻繁的修改,例如數(shù)據(jù)庫的用戶名和密碼信息, 建議采用傳統(tǒng)方法 (.txt , .properties , .xml)
模擬Junit
通過反射讀取字節(jié)碼上的注解信息
md.isAnnotationPresen)
元注解
注解的注解,
聲明當(dāng)前注解作用域以及目標(biāo)對象,如果沒有聲明,在運(yùn)行期間是無法獲取到注解的信息
@Runtention 聲明當(dāng)前注解的作用域
@target 聲明當(dāng)前注解的目標(biāo)對象
代碼實(shí)現(xiàn)
自定義注解@MyTest
//自定義注解,相當(dāng)于JUnit@Test
//定義注解的時(shí)候,需要通過元注解Retention說明當(dāng)前自定義注解的作用域(Class,Source,Runtime)
@Retention)
//定義注解的時(shí)候,需要通過元注解Target說明當(dāng)前的自定義注解的目標(biāo)對象
@Targe)
public @interface MyTest {
//在MyTest注解中定義成員屬性,默認(rèn)值為-1
public long timeout() default -1;
}
定義UserDao
public class UserDao {
static{
Sy("加載靜態(tài)代碼段的消息");
}
@MyTest
public void addUser(){
Sy("增加用戶");
}
@MyTest
public void delUser(){
Sy("刪除用戶");
}
@MyTest
public void uptUser(){
Sy("更新用戶");
}
public void getUser(){
Sy("獲取用戶");
}
}
定義類MyJunit ,模擬JUnit
public class MyJunit {
public static void main(String[] args) throws Exception {
//加載U字節(jié)碼文件中的方法,判斷哪些方法上有自定義的注解@MyTest,如果當(dāng)前的方法有@MyTest,執(zhí)行,否則不執(zhí)行
//1_將U字節(jié)碼文件加載到內(nèi)存中 ,class對象(代表字節(jié)碼文件在內(nèi)存中的對象)
Class clazz=Cla("com.i;);
Class claszz01=U;
Class claszz02=new UserDao().getClass();
//2_獲取字節(jié)碼對象上所有的方法,返回Method數(shù)組對象,數(shù)組中的每一個(gè)元素都代表Method對象(相當(dāng)于字節(jié)碼上的每一個(gè)方法)
Method[] mds = clazz.getMethods();
//3_遍歷字節(jié)碼對象上所有的方法
for (Method md : mds) {
//測試方法的名稱
//Sy());
//判斷當(dāng)前方法上是否有@MyTest注解信息
//Sy(md.isAnnotationPresen));
if(md.isAnnotationPresen)){
//如果當(dāng)前的方法上有@MyTest注解,執(zhí)行,否則忽略
md.invoke(new UserDao());
}
}
}
}
1.《程序中出現(xiàn)亂碼怎么辦看這里!java反射基礎(chǔ) && 動態(tài)代理解決亂碼問題 && 注解》援引自互聯(lián)網(wǎng),旨在傳遞更多網(wǎng)絡(luò)信息知識,僅代表作者本人觀點(diǎn),與本網(wǎng)站無關(guān),侵刪請聯(lián)系頁腳下方聯(lián)系方式。
2.《程序中出現(xiàn)亂碼怎么辦看這里!java反射基礎(chǔ) && 動態(tài)代理解決亂碼問題 && 注解》僅供讀者參考,本網(wǎng)站未對該內(nèi)容進(jìn)行證實(shí),對其原創(chuàng)性、真實(shí)性、完整性、及時(shí)性不作任何保證。
3.文章轉(zhuǎn)載時(shí)請保留本站內(nèi)容來源地址,http://f99ss.com/gl/3039292.html