日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程语言 > java >内容正文

java

java反射机制详解_Java反射机制详解

發(fā)布時間:2024/10/14 java 106 豆豆
生活随笔 收集整理的這篇文章主要介紹了 java反射机制详解_Java反射机制详解 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

Java反射機(jī)制是在運(yùn)行狀態(tài)中,對于任意一個類,都能夠知道這個類的所有屬性和方法;對于任意一個對象,都能夠調(diào)用它的任意一個方法和屬性;這種動態(tài)獲取的信息以及動態(tài)調(diào)用對象的方法的功能稱為Java語言的反射機(jī)制。

1、關(guān)于Class

1、Class是一個類,一個描述類的類(也就是描述類本身),封裝了描述方法的Method,描述字段的Filed,描述構(gòu)造器的Constructor等屬性

2、對象照鏡子后(反射)可以得到的信息:某個類的數(shù)據(jù)成員名、方法和構(gòu)造器、某個類到底實現(xiàn)了哪些接口。

3、對于每個類而言,JRE 都為其保留一個不變的 Class 類型的對象。

一個 Class 對象包含了特定某個類的有關(guān)信息。

4、Class 對象只能由系統(tǒng)建立對象

5、一個類在 JVM 中只會有一個Class實例

package?com.java.reflection;

public?class?Person?{

String?name;

private?int?age;

public?Person()?{

System.out.println("無參構(gòu)造器");

}

public?Person(String?name,?int?age)?{

System.out.println("有參構(gòu)造器");

this.name?=?name;

this.age?=?age;

}

public?String?getName()?{

return?name;

}

public?void?setName(String?name)?{

this.name?=?name;

}

public?int?getAge()?{

return?age;

}

public?void?setAge(int?age)?{

this.age?=?age;

}

@Override

public?String?toString()?{

return?"Person{"?+

"name='"?+?name?+?'\''?+

",?age="?+?age?+

'}';

}

}

2、反射機(jī)制獲取類有三種方法

/**

*?反射機(jī)制獲取類有三種方法

*/

@Test

public?void?testGetClass()?throws?ClassNotFoundException?{

Class?clazz?=?null;

//1?直接通過類名.Class的方式得到

clazz?=?Person.class;

System.out.println("通過類名:?"?+?clazz);

//2?通過對象的getClass()方法獲取,這個使用的少(一般是傳的是Object,不知道是什么類型的時候才用)

Object?obj?=?new?Person();

clazz?=?obj.getClass();

System.out.println("通過getClass():?"?+?clazz);

//3?通過全類名獲取,用的比較多,但可能拋出ClassNotFoundException異常

clazz?=?Class.forName("com.java.reflection.Person");

System.out.println("通過全類名獲取:?"?+?clazz);

}

通過類名: class com.java.reflection.Person

無參構(gòu)造器

通過getClass(): class com.java.reflection.Person

通過全類名獲取: class com.java.reflection.Person

3、利用newInstance創(chuàng)建對象:調(diào)用的類必須有無參的構(gòu)造器

/**

*?Class類的newInstance()方法,創(chuàng)建類的一個對象。

*/

@Test

public?void?testNewInstance()

throws?ClassNotFoundException,?IllegalAccessException,?InstantiationException?{

Class?clazz?=?Class.forName("com.java.reflection.Person");

//使用Class類的newInstance()方法創(chuàng)建類的一個對象

//實際調(diào)用的類的那個?無參數(shù)的構(gòu)造器(這就是為什么寫的類的時候,要寫一個無參數(shù)的構(gòu)造器,就是給反射用的)

//一般的,一個類若聲明了帶參數(shù)的構(gòu)造器,也要聲明一個無參數(shù)的構(gòu)造器

Object?obj?=?clazz.newInstance();

System.out.println(obj);

}

無參構(gòu)造器

Person{name='null', age=0}

4、ClassLoader類加載器

/**

*?ClassLoader類裝載器

*/

@Test

public?void?testClassLoader1()?throws?ClassNotFoundException,?IOException?{

//1、獲取一個系統(tǒng)的類加載器

ClassLoader?classLoader?=?ClassLoader.getSystemClassLoader();

System.out.println("系統(tǒng)的類加載器-->"?+?classLoader);

//2、獲取系統(tǒng)類加載器的父類加載器(擴(kuò)展類加載器(extensions?classLoader))

classLoader?=?classLoader.getParent();

System.out.println("擴(kuò)展類加載器-->"?+?classLoader);

//3、獲取擴(kuò)展類加載器的父類加載器

//輸出為Null,無法被Java程序直接引用

classLoader?=?classLoader.getParent();

System.out.println("啟動類加載器-->"?+?classLoader);

//

//4、測試當(dāng)前類由哪個類加載器進(jìn)行加載?,結(jié)果就是系統(tǒng)的類加載器

classLoader?=?Class.forName("com.java.reflection.Person").getClassLoader();

System.out.println("當(dāng)前類由哪個類加載器進(jìn)行加載-->"+classLoader);

//5、測試JDK提供的Object類由哪個類加載器負(fù)責(zé)加載的

classLoader?=?Class.forName("java.lang.Object").getClassLoader();

System.out.println("JDK提供的Object類由哪個類加載器加載-->"?+?classLoader);

}

系統(tǒng)的類加載器-->sun.misc.Launcher$AppClassLoader@43be2d65

擴(kuò)展類加載器-->sun.misc.Launcher$ExtClassLoader@7a9664a1

啟動類加載器-->null

當(dāng)前類由哪個類加載器進(jìn)行加載-->sun.misc.Launcher$AppClassLoader@43be2d65

JDK提供的Object類由哪個類加載器加載-->null

4.1、getResourceAsStream方法

@Test

public?void?testGetResourceAsStream()?throws?ClassNotFoundException,?IOException?{

//??????????這么寫的話,文件需要放到src目錄下

//???????InputStream?in?=?new?FileInputStream("test.properties");

//5、關(guān)于類加載器的一個主要方法

//調(diào)用getResourceAsStream?獲取類路徑下的文件對應(yīng)的輸入流

InputStream?in?=?this.getClass().getClassLoader()

.getResourceAsStream("com/java/reflection/test.properties");

System.out.println("in:?"?+in);

Properties?properties?=?new?Properties();

properties.load(in);

String?driverClass?=?properties.getProperty("dirver");

String?jdbcUrl?=?properties.getProperty("jdbcUrl");

//中文可能會出現(xiàn)亂碼,需要轉(zhuǎn)換一下

String?user?=?new?String(properties.getProperty("user").getBytes("ISO-8859-1"),?"UTF-8");

String?password?=?properties.getProperty("password");

System.out.println("diverClass:?"+driverClass);

System.out.println("user:?"?+?user);

}

test.properties內(nèi)容如下:

dirver=com.mysql.jdbc.Driver;

jdbcUrl=jdbc:mysql://192.168.42.108:3306/test

user=測試

password=993803

結(jié)果:

in: java.io.BufferedInputStream@2aca0115

diverClass: com.mysql.jdbc.Driver;

user: 測試

5、Method: 對應(yīng)類中的方法

public?class?Person?{

private?String?name;

private?int?age;

//新增一個私有方法

private?void?privateMthod(){

}

public?Person()?{

System.out.println("無參構(gòu)造器");

}

public?Person(String?name,?int?age)?{

System.out.println("有參構(gòu)造器");

this.name?=?name;

this.age?=?age;

}

public?String?getName()?{

return?name;

}

public?void?setName(String?name)?{

this.name?=?name;

}

/**

*

*?@param?age??類型用Integer,不用int

*/

public?void?setName(String?name?,?int?age){

System.out.println("name:?"?+?name);

System.out.println("age:"+?age);

}

public?int?getAge()?{

return?age;

}

public?void?setAge(int?age)?{

this.age?=?age;

}

@Override

public?String?toString()?{

return?"Person{"?+

"name='"?+?name?+?'\''?+

",?age="?+?age?+

'}';

}

}

@Test

public?void?testMethod()?throws?ClassNotFoundException,?NoSuchMethodException,

IllegalAccessException,?InstantiationException,?InvocationTargetException?{

Class?clazz?=?Class.forName("com.java.reflection.Person");

//1、得到clazz?對應(yīng)的類中有哪些方法,不能獲取private方法

Method[]?methods?=clazz.getMethods();

System.out.print("????????getMethods:?");

for?(Method?method?:?methods){

System.out.print(method.getName()?+?",?");

}

//2、獲取所有的方法(且只獲取當(dāng)著類聲明的方法,包括private方法)

Method[]?methods2?=?clazz.getDeclaredMethods();

System.out.print("\ngetDeclaredMethods:?");

for?(Method?method?:?methods2){

System.out.print(method.getName()?+?",?");

}

//3、獲取指定的方法

Method?method?=?clazz.getDeclaredMethod("setName",String.class);//第一個參數(shù)是方法名,后面的是方法里的參數(shù)

System.out.println("\nmethod?:?"?+?method);

Method?method2?=?clazz.getDeclaredMethod("setName",String.class?,int.class);//第一個參數(shù)是方法名,后面的是方法里的參數(shù)

System.out.println("method2:?"?+?method2);

//4、執(zhí)行方法!

Object?obj?=?clazz.newInstance();

method2.invoke(obj,?"changwen",?22);

}

getMethods: toString, getName, setName, setName, setAge,

getAge, wait, wait, wait, equals, hashCode, getClass, notify, notifyAll,

getDeclaredMethods: toString, getName, setName, setName, setAge, getAge, privateMthod,

method : public void com.java.reflection.Person.setName(java.lang.String)

method2: public void com.java.reflection.Person.setName(java.lang.String,int)

無參構(gòu)造器

name: changwen

age:22

6、invoke方法

public?class?PersonInvoke?{

public?PersonInvoke()?{

}

private?String?method2()?{

return?"Person?private?String?method2";

}

}

public?class?StudentInvoke?extends?PersonInvoke{

private?void?method1(Integer?age)?{

System.out.println("Student?private?void?method1,?age=:"?+age);

}

}

獲取當(dāng)前類的父類定義的私有方法

/**

*?獲取當(dāng)前類的父類中定義的私有方法

*?直接調(diào)用getSuperclass()

*/

@Test

public?void?testGetSuperClass()?throws?Exception?{

String?className?=?"com.java.reflection.StudentInvoke";

Class?clazz?=?Class.forName(className);

Class?superClazz?=?clazz.getSuperclass();

System.out.println(superClazz);

//輸出結(jié)果:class?com.java.reflection.PersonInvoke

}

另一種寫法

/**

*?@param?className??某個類的全類名

*?@param?methodName?類的一個方法的方法名,該方法也可能是私有方法

*?@param?args??調(diào)用該方法需要傳入的參數(shù)?...可變參數(shù)的意思

*?@return?調(diào)用方法后的返回值

*/

public?Object?invoke(String?className,?String?methodName,?Object?...?args)?{

Object?obj?=?null;

try?{

obj?=?Class.forName(className).newInstance();

return?invoke(obj,?methodName,?args);

}?catch?(InstantiationException?e)?{

e.printStackTrace();

}?catch?(IllegalAccessException?e)?{

e.printStackTrace();

}?catch?(ClassNotFoundException?e)?{

e.printStackTrace();

}

return?invoke(null,?methodName,?args);

}

/**

*?@param?obj??方法執(zhí)行的那個對象

*?@param?methodName?類的一個方法的方法名,該方法也可能是私有方法,還可能是該方法在父類中定義的私有方法

*?@param?args??調(diào)用該方法需要傳入的參數(shù)?...可變參數(shù)的意思

*?@return?調(diào)用方法后的返回值

*/

public?Object?invoke(Object?obj,?String?methodName,?Object?...?args)?{

//1、獲取Method對象

Class?[]?parameterTypes?=?new?Class[args.length];

for?(int?i=0?;?i

parameterTypes[i]?=?args[i].getClass();

}

try?{

//2、執(zhí)行Method方法

Method?method?=?getMethod(obj.getClass(),?methodName,parameterTypes);

//通過反射執(zhí)行private方法

method.setAccessible(true);

//3、返回方法的返回值

return?method.invoke(obj,args);

}?catch?(Exception?e)?{

}

return?null;

}

/**

*?獲取clazz?的methodName?方法,?該方法可能是私有方法,還可能是父類中的私有方法

*/

public?Method?getMethod(Class?clazz,?String?methodName,?Class?...?parameterTypes)?{

//注意這個循環(huán)里的內(nèi)容!!!

for?(;?clazz?!=?Object.class;?clazz?=?clazz.getSuperclass()){

try?{

return?clazz.getDeclaredMethod(methodName,?parameterTypes);

}?catch?(Exception?e)?{?//這里要寫Exception,不然會出錯,應(yīng)該是有部分異常沒有捕獲

}

}

return?null;

}

測試:

@Test

public?void?testInvoke2()?{

Object?obj?=?new?StudentInvoke();

invoke(obj,?"method1",?10);

Object?result?=?invoke(obj,?"method2");

System.out.println(result);

}

private void method1,age:10

Person private String method2

7、Field字段

public?class?Person?{

public?String?name;

private?Integer?age;

public?Person()?{

}

public?Person(String?name,?Integer?age)?{

this.name?=?name;

this.age?=?age;

}

}

/**

*?Field:?封裝了字段的信息

*/

@Test

public?void?testField()?throws

ClassNotFoundException,?NoSuchFieldException,?IllegalAccessException?{

Class?clazz?=?Class.forName("com.java.reflection.Person");

//1、獲取字段

//1.1?獲取Field的數(shù)組,私有字段也能獲取

Field[]?fields?=?clazz.getDeclaredFields();

for?(Field?field:?fields)?{

System.out.print(field.getName()?+?",?");

}

//1.2?獲取指定名字的Field(如果是私有的,見下面的4)

Field?field?=?clazz.getDeclaredField("name");

System.out.println("\n獲取指定Field名=:?"?+?field.getName());

Person?person?=?new?Person("ABC",?12);

//2、獲取指定對象的Field的值

Object?val?=?field.get(person);

System.out.println("獲取指定對象字段'name'的Field的值=:?"?+?val);

//3、設(shè)置指定對象的Field的值

field.set(person,?"changwen2");

System.out.println("設(shè)置指定對象字段'name'的Field的值=:?"?+?person.name);

//4、若該字段是私有的,需要調(diào)用setAccessible(true)方法

Field?field2?=?clazz.getDeclaredField("age");

field2.setAccessible(true);

System.out.println("獲取指定私有字段名=:?"?+?field2.getName());

}

name, age,

獲取指定Field名=: name

獲取指定對象字段'name'的Field的值=: ABC

設(shè)置指定對象字段'name'的Field的值=: changwen2

獲取指定私有字段名=: age

/**

*?一個實例:

*?反射獲取一個繼承Person2的Student類

*?設(shè)置字段"age"=20(該字段可能為私有,可能在其父類中)

*/

@Test

public?void?testClassField()?throws?ClassNotFoundException,?IllegalAccessException,?InstantiationException?{

String?className?=?"com.java.reflection.Student";

String?fieldName?=?"age";??//可能為私有,可能在其父類中

Object?val?=?20;

//創(chuàng)建className?對應(yīng)類的對象,并為其fieldName賦值為val

Class?clazz?=?Class.forName(className);

Field?field?=?null;

for?(Class?clazz2?=?clazz;?clazz2?!=?Object.class;?clazz2?=?clazz2.getSuperclass()){

try?{

field?=?clazz2.getDeclaredField(fieldName);

}?catch?(Exception?e)?{

}

}

Object?obj?=?clazz.newInstance();

assert?field?!=?null;

field.setAccessible(true);

field.set(obj,?val);

Student?stu?=?(Student)?obj;

System.out.println("age?=?"?+?stu.getAge());

}

8、構(gòu)造器(Constructor)

/**

*?構(gòu)造器:開發(fā)用的比較少

*/

@Test

public?void?testConstructor()?throws?ClassNotFoundException,?NoSuchMethodException,

IllegalAccessException,?InvocationTargetException,?InstantiationException?{

String?className?=?"com.java.reflection.Person";

Class?clazz?=?(Class)?Class.forName(className);

//1.獲取Constructor對象

Constructor[]?constructors?=

(Constructor[])?Class.forName(className).getConstructors();

for?(Constructor?constructor:?constructors)?{

System.out.println(constructor);

}

Constructor?constructor?=?clazz.getConstructor(String.class,?Integer.class);

System.out.println("指定的-->"?+?constructor);

//2.調(diào)用構(gòu)造器的newInstance()方法創(chuàng)建對象

Object?obj=?constructor.newInstance("changwen",?11);

}

public com.java.reflection.Person()

public com.java.reflection.Person(java.lang.String,java.lang.Integer)

指定的-->public com.java.reflection.Person(java.lang.String,java.lang.Integer)

9、注解(Annotation)

?從?JDK5.0?開始,Java?增加了對元數(shù)據(jù)(MetaData)的支持,也就是Annotation(注釋)

?Annotation其實就是代碼里的特殊標(biāo)記,這些標(biāo)記可以在編譯,類加載,?運(yùn)行時被讀取,并執(zhí)行相應(yīng)的處理.通過使用Annotation,程序員可以在不改變原有邏輯的情況下,在源文件中嵌入一些補(bǔ)充信息.

?Annotation?可以像修飾符一樣被使用,可用于修飾包,類,構(gòu)造器,?方法,成員變量,?參數(shù),局部變量的聲明,這些信息被保存在Annotation的?“name=value”對中.

?Annotation能被用來為程序元素(類,方法,成員變量等)設(shè)置元數(shù)據(jù)

基本的?Annotation

?使用?Annotation時要在其前面增加@符號,并把該Annotation?當(dāng)成一個修飾符使用.用于修飾它支持的程序元素

?三個基本的Annotation:

–@Override:限定重寫父類方法,該注釋只能用于方法

–@Deprecated:用于表示某個程序元素(類,方法等)已過時

–@SuppressWarnings:抑制編譯器警告.

自定義?Annotation

?定義新的?Annotation類型使用@interface關(guān)鍵字

?Annotation?的成員變量在Annotation?定義中以無參數(shù)方法的形式來聲明.其方法名和返回值定義了該成員的名字和類型.

?可以在定義Annotation的成員變量時為其指定初始值,指定成員變量的初始值可使用default關(guān)鍵字

?沒有成員定義的Annotation稱為標(biāo)記;包含成員變量的Annotation稱為元數(shù)據(jù)Annotation

@Retention(RetentionPolicy.RUNTIME)?//運(yùn)行時檢驗

@Target(value?=?{ElementType.METHOD})??//作用在方法上

public?@interface?AgeValidator?{

int?min();

int?max();

}

/**

*?通過反射才能獲取注解

*/

@Test

public?void?testAnnotation()?throws?Exception?{

//這樣的方式不能使用注解

Person3?person3?=?new?Person3();

person3.setAge(10);*/

String?className?=?"com.java.reflection.Person3";

Class?clazz?=?Class.forName(className);

Object?obj?=?clazz.newInstance();

Method?method?=?clazz.getDeclaredMethod("setAge",Integer.class);

int?val?=40;

//獲取注解

Annotation?annotation?=?method.getAnnotation(AgeValidator.class);

if?(annotation?!=?null){

if?(annotation?instanceof?AgeValidator){

AgeValidator?ageValidator?=?(AgeValidator)?annotation;

if?(valageValidator.max()){

throw?new?RuntimeException("數(shù)值超出范圍");

}

}

}

method.invoke(obj,?val);

System.out.println(obj);

}

提取?Annotation信息

?JDK5.0?在?java.lang.reflect包下新增了?AnnotatedElement接口,該接口代表程序中可以接受注釋的程序元素

?當(dāng)一個?Annotation類型被定義為運(yùn)行時Annotation后,該注釋才是運(yùn)行時可見,當(dāng)?class文件被載入時保存在?class文件中的?Annotation才會被虛擬機(jī)讀取

?程序可以調(diào)用AnnotationElement對象的如下方法來訪問?Annotation信息

–獲取?Annotation實例:

?getAnnotation(Class?annotationClass)

JDK?的元Annotation

?JDK?的元Annotation?用于修飾其他Annotation?定義

?@Retention:只能用于修飾一個?Annotation定義,用于指定該?Annotation可以保留多長時間,@Rentention包含一個RetentionPolicy類型的成員變量,使用?@Rentention時必須為該?value成員變量指定值:

–RetentionPolicy.CLASS:編譯器將把注釋記錄在?class文件中.當(dāng)運(yùn)行?Java程序時,JVM?不會保留注釋.這是默認(rèn)值

–RetentionPolicy.RUNTIME:編譯器將把注釋記錄在class文件中.?當(dāng)運(yùn)行?Java?程序時, JVM?會保留注釋.?程序可以通過反射獲取該注釋

–RetentionPolicy.SOURCE:編譯器直接丟棄這種策略的注釋

?@Target:?用于修飾Annotation?定義,用于指定被修飾的?Annotation能用于修飾哪些程序元素.@Target?也包含一個名為?value的成員變量.

?@Documented:用于指定被該元?Annotation修飾的?Annotation類將被?javadoc工具提取成文檔.

?@Inherited:被它修飾的?Annotation將具有繼承性.如果某個類使用了被@Inherited?修飾的Annotation,?則其子類將自動具有該注釋

總結(jié)

以上是生活随笔為你收集整理的java反射机制详解_Java反射机制详解的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。