上周記錄了java基礎(chǔ)之注解(Annotation)瞻赶,這周他的好基友“反射”如約而至(明明是姍姍來遲~)澳骤。
反射的基本概念
反射機(jī)制是在運(yùn)行狀態(tài)中醋闭,對于任意一個類鲤看,都能夠知道這個類的所有屬性和方法宅广;對于任意一個對象葫掉,都能夠調(diào)用它的任意一個方法和屬性;這種動態(tài)獲取的信息以及動態(tài)調(diào)用對象的方法的功能稱為java語言的反射機(jī)制跟狱。
反射的基石:class類
Class類的各個實例對象分別對應(yīng)各個類在內(nèi)存中的字節(jié)碼,例如TestModel類的字節(jié)碼户魏,ArrayList類的字節(jié)碼驶臊,等等。
一個類被類加載器加載到內(nèi)存中叼丑,占用一片存儲空間关翎,這個空間里面的內(nèi)容就是類的字節(jié)碼,不同的類的字節(jié)碼是不同的鸠信,所以他們在內(nèi)存中的內(nèi)容是不同的纵寝,這一個個空間可分別用一個個對象來表示,這些對象顯然具有相同的類型星立,這個類型就是Class類型
這里一定要分清一個對象的Class類型和對象的內(nèi)容爽茴。 兩個不同的對象是可以有相同的Class類型的。
比如說: 下面兩個字符串明顯不是同一個的對象绰垂,但他們的Class類型是一樣的:java.lang.String
String str1 = "abc";//字符串1
String str2 = "abcd";//字符串2
反射常用方法
實例化Class類對象
Class clazz = Class.forName("java.lang.String");
Class clazz = new String().getClass();
Class clazz = String.class;
Class中的Constructor類室奏,實例化一個對象
/**獲取String對象的所有構(gòu)造方法*/
Constructor[] constructors = Class.forName("java.lang.String").getConstructors();
/**獲取String默認(rèn)的構(gòu)造方法生成String對象*/
String str = String.class.newInstance();
/**獲取String對象指定的構(gòu)造方法(通過方法的參數(shù)類型,傳遞參數(shù)的Class對象)*/
Constructor constructor = String.class.getConstructor(StringBuffer.class);
String str = (String) constructor.newInstance(new StringBuffer("abc"));
Class中的Field類
/**獲取clazz這個Class的所有字段*/
Field[] fields = clazz.getDeclaredFields();
//獲取clazz的字段名為“X”的字段
//getField方法只能獲取到public字段,getDeclaredField可以獲取到所有的字段
Field field = clazz.getDeclaredField("x");
//對于private修飾的字段需要設(shè)置Accessible為true
field.setAccessible(true);
//設(shè)置和獲取field的屬性
field.set(testModel, (String)name.value());
field.get(obj);
//獲取字段的類型
field.getGenericType()
//判斷是否有TestAnnotationName注解
field.isAnnotationPresent(TestAnnotationName.class)
//獲取字段上的注解
field.getAnnotation(annotationClass)
Class中的Method類
獲取Method的方法和獲取field的方法基本一致
//獲取所有方法
Method[] methods = clazz.getDeclaredMethods();
//獲取對應(yīng)方法
Method methodCharAt = clazz.getMethod("charAt", int.class);
//調(diào)用方法
methodCharAt.invoke(object,18);
獲取一個對象的父類與實現(xiàn)的接口
// 取得父類
Class<?> parentClass = clazz.getSuperclass();
// 獲取所有的接口
Class<?> intes[] = clazz.getInterfaces();
使用反射解析注解
終于說到注解了
聲明注解
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface TestAnnotationAge{
int value() default 18;
}
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface TestAnnotationName{
String value() default "aclululu";
}
設(shè)置注解
public class TestModel {
@TestAnnotationName
private String name;
@TestAnnotationAge
private int age;
/**省略getter setter方法**/
}
解析注解
public static void main(String[] args) throws IllegalArgumentException, IllegalAccessException {
TestModel testModel = new TestModel();
System.out.println(testModel.toString());
System.out.println("通過反射機(jī)制將注解信息設(shè)置給Model...");
Class clazz = TestModel.class;
Field[] fields = clazz.getDeclaredFields();
for(Field field :fields){
if(field.isAnnotationPresent(TestAnnotationName.class)){
TestAnnotationName name = (TestAnnotationName) field.getAnnotation(TestAnnotationName.class);
field.setAccessible(true);
field.set(testModel, (String)name.value());
}
else if(field.isAnnotationPresent(TestAnnotationAge.class)){
TestAnnotationAge age= (TestAnnotationAge) field.getAnnotation(TestAnnotationAge.class);
field.setAccessible(true);
field.set(testModel, (int)age.value());
}
}
System.out.println(testModel.toString());
}
輸出結(jié)果
TestModel [age=0, name=null]
通過反射機(jī)制將注解信息設(shè)置給Model...
TestModel [age=18, name=aclululu]