注解與反射
注解
注解(Annotation) 可以被其他程序(如:編譯器)讀取
? 可通過反射機制編程實現對這些元數據的訪問
注解都定義在 java.lang.* 下
@Verride //重寫的注解
@Deprecated // 已過時的,表示不鼓勵程序員使用這樣的元素(很危險或有更好的選擇)
@SuppressWarnings // 鎮壓警告
@SuppressWarnings("all") // 鎮壓所有的警告
元注解
元注解作用是負責注解其他注解
@Target // 用于描述注解的使用范圍(被描述的注解可用于什么地方)
@Retention //表示需要在什么級別保存該注釋信息(SOURCE < CLASS < RUNTIME)
@Document // 說明該注釋將被包含在javadoc 中
@Inherited // 說明子類可以繼承父類中的該注解
反射(Reflection)
反射:加載類,允許以編程的方式拿出類中各種成分(成員變量、方法、構造器等)
1、 反射第一步:加載類,獲取類的字節碼:Class 對象
2、 獲取類的構造器 : Constructor 對象
3、 獲取類的成員變量:Field 對象
4、 獲取類的成員方法:Method 對象
獲取Class 對象的三種方法
Class c1 = 類名.class
調用Class 提供的方法 : public static Class forName(String package);
Object提供的方法: public Class getClass(); Class c3 = 對象.getClass();
獲取反射的字節碼文件
Class c1 = 類名.class
c1.getName(); // 返回此字節碼類的全類名
c1.getSimpleName(); // 返回字節碼類的簡名字:類名
Class c2 = Class.forName("com.whoami.Test");
System.out.print(c1 == c2); // 兩種方法拿到的為同一個class 文件
Test t = new Test();
Class c3 = t.getClass();
System.out.print(c3 == c2); //三種方法拿到的為同一個class 文件
獲取反射的類中構造器
作用:依然是初始化對象返回
Class c = Test.class // 獲取類的字節碼文件
Constructor[] constructors = c.getConstructors(); // 通過字節碼文件獲取到類的所有構造器(只能獲取public修飾的構造器)
c.getDeclaredConstructors(); // 獲取類中所有的構造器
c.getConstructor(); // 獲取單個構造器(只有public 修飾)
c.getDeclaredConstructor(); // 獲取單個構造器
c.getConstructor(String.class,int.class); // 匹配有參構造器
for(Constructor construcotr : constructors){
constructor.getName // 獲取構造器名字
constructor.getParameterCount(); // 獲取構造器參數
}
constructor1.newInstance(); // 調用構造器對象表示的構造器,并傳入參數,完成初始化
constuctor1.setAccessible(true); // 禁止檢查訪問權限,即此反射構造器可調用私有屬性
獲取類的成員變量
作用:依然是賦值、取值
1、 反射第一步:必須是先得到類的Class 對象
Class c = Cat.class;
2、 獲取類的全部成員變量
Field[] fields = c.getDeclaredFields(); // 獲取類的全部成員變量
c.getFields(); // 獲取類的全部成員變量(只獲取public 的)
Field fName = c.getField("變量名"); // 獲取某個成員變量(只能獲取public 的)
c.getDeclaredField("變量名"); // 獲取某個成員變量
for (Field field : fields){
field.getName() ; // 獲取變量名
firld.getType(); // 獲取變量類型
}
1、取值、賦值
Class c = Test01.class;
Test01 test01 = new Test01();
Field fName = c.getDeclaredField("name")
//賦值
Test01 test01 = new Test01();
fName.setAccessible(true); // 禁止訪問控制權限,暴力反射
fName.set(test01,"咖啡貓"); // 賦予test對象(即Test01類)成員變量值
//取值
String name = (String) fNmae.get(test01); // 取出類中的fName的變量名的屬性值
獲取類的成員方法
作用:依然是執行
Class c = Test01.class;
Method[] methods = c.getDeclaredMethods(); // 獲取類的全部成員方法
c.getMethods(); // 獲取類的全部成員方法(只有public 修飾)
c.getMethod("run",param); // 獲取某個成員方法(run方法+參數匹配) (只有public 修飾)
c.getDeclareMethod("run",param); // 獲取某個成員方法(run方法+參數匹配)
Class c = Test01.class;
Test01 test01 = new Test01();
run.setAccessible(true); // 暴力強轉
Object result = run.invoke(test01,param); // 觸發某個對象中的方法執行(返回值為Object,返回值可指定)
反射的作用
基本作用 :可以得到一個類的全部成分然后操作
可以破壞封裝性
最重要的用途:適合做Java 的框架,基本上,主流的框架都會基于反射設計出一些通用的功能
注解
讓其他程序根據注解信息來決定怎么執行該程序
自定義注解
public @interface 注解名稱{
public 屬性類型 屬性名() default 默認值;
}
// 例
public @interface MyTest1{
String aaa();
boolean bbb() default true;
Stringp[] ccc();
}
特殊屬性名:value
如果注解中只有一個value 屬性,使用注解時,value名稱可以不寫
注解的本質是一個接口,Java中的所有注解都是繼承了Annotation 接口
@注解(...): 其本質就是一個實現類對象
元注解
修飾注解的注解
@Target // 作用:聲明被修飾的注解只能在哪些位置使用
@Target(ElementType.TYPE)
1. TYPE, 類,接口
2. FIELD, 成員變量
3. METHOD, 成員方法
4. PARAMETER, 方法參數
5. CONSTRUCTOR, 構造器
6. LOCAL_VARLABLE,局部變量
@Retention // 作用:聲明注解的保留周期
@Retention(RetentionPolicy.RUNTIME)
1.SOUCE // 只作用于源碼階段,字節碼文件中不存在
2.CLASS (默認值) // 保留到字節碼文件階段,運行階段不存在
3.RUNTIM(開發常用) // 一直保留到運行階段
注解的解析
判斷類上、方法上、成員變量上是否存在注解,并把注解里的內容解析出來
指導思想:要解析誰上面的注解,就應該先拿到誰
Class c = Demo.class; // 聲明取出class 類的反射字節
Method m = c.getDeclaredMethod("test1") // 從反射的class 對象中獲得成員方法
if(m.isAnnotationPresent(MyTest.class)){ // isAnnotationPresent(),判斷此類/方法/變量是否存在指定的注解,返回boolen
MyTest4 mytest4 = (MyTest4) m.getDeclaredAnnotation(MyTest.class); // 指定注解并取出,返回值為Annotation 類
m.getDeclareAnnotations() // 獲取當前對象上面的注解
mytest4.value();
mytest4.aaa();
mytest4.bbb();
}
注解的應用場景
package zhujie;
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Arrays;
public class AnnotationTest3 {
@MYTest
public void test1(){
System.out.println("test1");
}
@MYTest
public void test2(){
System.out.println("test2");
}
@MYTest
public void test3(){
System.out.println("test3");
}
@MYTest
public void test4(){
System.out.println("test4");
}
public static void main(String[] args) throws Exception{
AnnotationTest3 annotation = new AnnotationTest3(); // new 對象,用于invoke 執行方法時使用到
Class c = AnnotationTest3.class; // 利用反射定義class 對象為當前類
Method[] methods=c.getDeclaredMethods(); // 利用當前類的class 對象取出所有的方法
for (Method method : methods) { // 對于所有的方法進行循環
if(method.isAnnotationPresent(MYTest.class)){ // 對于循環的每一個反射的方法進行判斷,判斷是否存在MYTest 注解
method.invoke(annotation); // 若存在則進行invoke 執行該函數
}
}
}
}

浙公網安備 33010602011771號