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ǔ) &amp;&amp; 動態(tài)代理解決亂碼問題 &amp;&amp; 注解》援引自互聯(lián)網(wǎng),旨在傳遞更多網(wǎng)絡(luò)信息知識,僅代表作者本人觀點(diǎn),與本網(wǎng)站無關(guān),侵刪請聯(lián)系頁腳下方聯(lián)系方式。

2.《程序中出現(xiàn)亂碼怎么辦看這里!java反射基礎(chǔ) &amp;&amp; 動態(tài)代理解決亂碼問題 &amp;&amp; 注解》僅供讀者參考,本網(wǎng)站未對該內(nèi)容進(jìn)行證實(shí),對其原創(chuàng)性、真實(shí)性、完整性、及時(shí)性不作任何保證。

3.文章轉(zhuǎn)載時(shí)請保留本站內(nèi)容來源地址,http://f99ss.com/gl/3039292.html