反射与注解
反射
通過某種機制,動態(tài)得到這個類的所有信息(屬性,方法,構造方法),也可以動態(tài)的調用這個類所有的屬性,方法,構造方法... 這種機制就是所謂的反射
反射的核心:類的鏡子,類的字節(jié)碼文件 對應的類:Class類
每一個類,它的Class類的對象,唯一一個,類的Class對象, 在這個類的字節(jié)碼文件加載到內存時候,JVM就會為該類的字節(jié)碼文件創(chuàng)建一個Class對象
與new對象不同
不確定的類、不確定的對象創(chuàng)建 在框架底層 使用反射
反射的使用
創(chuàng)建對象
得到某個類的Class對象
1) 類名.class()
Class<Student> clazz = Student.class;2) 類的對象.getClass()
Student stu = new Student(); Class<? extends Student> clazz2 = stu.getClass();//Student本類 子類 上界 ?泛型通配符3)通過Class類的static方法:forName(類的全限定名:包名.類名)
Class<?> clazz3 = Class.forName("com.fs.Student");從這個Class對象獲取某個類所有的屬性,方法,構造方法
通過Class對象,調用屬性,方法
創(chuàng)建這個對象,類名是可變的String 如"Student","Dog"
new Student() 不可變 固定
獲取構造方法
方法,構造方法,屬性,參數都可以看作是一個個對象
getConstructor() getConstructors()
<init>(int) 表示的構造方法
// NoSuchMethodException異常: 沒有匹配的方法的異常
Constructor[] constructors = clazz.getConstructors(); //只能得到公開的構造方法 ? Constructor c1 = clazz.getDeclaredConstructor(int.class,String.class);//得到所有的 不管是公開還是私有指定參數類型的構造方法
.getModifiers() 得到訪問修飾符 返回值int 0. 缺省的 1. public 2. private 4. protected
用構造方法創(chuàng)建對象 new 構造方法() 創(chuàng)建對象
反射方式創(chuàng)建對象:
1)通過Class類的newInstance(),底層調用本類的無參構造方法
?Student stu = ?clazz.newInstance(); ? // new Student()2)通過構造方法對象的Constructor類newInstance(Object obj)
Constructor<Student> c = clazz.getDeclaredConstructor(int.class); c.Accessble(true);//如果調用的類的private修飾的屬性無法訪問,設置允許訪問 Student stu = c.newInstance();獲取屬性
Field
//獲得所有的public修飾的屬性(繼承自父類的屬性也能獲得),private修飾的屬性不能獲得 Field [] fs = cls.getFields(); ? Field [] fs = cls.getDeclaredFields(); // 獲得本類所有的屬性 for(int i=0;i<fs.length;i++){System.out.println(fs[i]); } ? //獲得指定的屬性 Field f = cls.getDeclaredField("mastername"); //mastername屬性為私有的,所以要先解除封裝 f.setAccessible(true); ? ? //修改指定的屬性 Field f = cls.getDeclaredField("mastername"); f.setAccessible(true); f.set(obj, "lisi"); System.out.println(f.get(obj));獲取方法
//獲得所有的方法,包括繼承自父類的方法,但只能是public 修飾的方法 Method[] ms = ?cls.getMethods(); ? //獲得本類所有的方法,不包括繼承自父類的方法,但private 修飾的方法也能獲得 Method[] ms = ?cls.getDeclaredMethods(); ? noSuchMethodException 找不到方法異常 ? //方法的執(zhí)行 //通過invoke調用方法,obj表示在哪個對象里調用方法,后續(xù)的參數都是方法的傳入的參數 //invoke返回值:如果方法為void 返回值為null String str = (String) ms.invoke(obj, "測試有參方法"); System.out.println("方法執(zhí)行的結果:"+str); ? I getName() //獲取全限定名 包名 +類名 getSimpleName() // 只得到類名注解
// /** */ /**/ 注釋:便于閱讀代碼,對代碼的描述
注解(Annotation):對代碼的描述,作為代碼的形式保留
Annontation像一種修飾符一樣,應用于包、類型、構造方法、方法、成員變量、參數及本地變量的聲明語句中。
注釋類似于商品的標簽,描述商品;注解類似于商品的條形碼,方便后期結算。
注解的作用
生成文檔
實現代替配置文件功能
在編譯時進行格式檢查 如 @Override 重寫 方法名和參數必須相同
注解的本質:特殊的接口
聲明注解:創(chuàng)建了一個特殊接口
使用注解: @注解名 (創(chuàng)建注解的一個對象)
注解的分類
內置注解
jdk提供的這個注解的聲明,開發(fā)者直接使用
@Override檢查重寫
@Deprecated 標記這個方法已過時
@SupperssWarnings抑制生成警告信息
1900~1999 計算機元年 1970年
元注解
使用元注解,對自定義的注解進行聲明,限制使用區(qū)域
1.@Documented-注解是否將包含在JavaDoc中
2.@Retention–什么時候使用該注解 Retention 保留期 存活時間
????????自定義注解一定設置為runtime
RetentionPolicy.RUNTIME 注解可以保留到程序運行的時候,它會被加載進入到 JVM 中,所以在程序運行時可以獲取到它們。
RetentionPolicy.SOURCE注解只在源碼階段保留,在編譯器進行編譯時它將被丟棄忽視。
RetentionPolicy.CLASS注解只被保留到編譯進行的時候,它并不會被加載到 JVM 中。
3.?@Target–注解用于什么地方 如果沒有寫,表示這個注解可以在任意地方使用
注解可以使用在 類、方法、屬性 上
給注解的參數賦值
如果給注解定義的參數是數組類型,給數組類型賦值
賦一個值@Target(value = {ElementType.TYPE})描述類、接口或enum聲明
賦多個值 @Target(value = {ElementType.TYPE,ElementType.METHOD})描述類、接口或enum聲明和方法
4.@Inherited– 定義該注釋和子類的關系 Inherited 繼承 子類可以繼承父類的注解
自定義注解
聲明注解的語法:@interface 默認繼承Annotation
參數成員訪問修飾符只能為默認default或public 方法返回值
? @Target(ElementType.FIELD)//可以用來修飾對象,屬性 @Retention(RetentionPolicy.RUNTIME)//什么時候都不丟棄 @Documented//用于生成javadoc文檔 public @interface 注解名{//成員:常量 //String value() defualt ="zhangsan"; 給參數賦值就是給方法的返回值String value();//如果沒有設置default默認值,使用這個注解時一定要給參數賦值//如果設置了default,可以在使用時改變默認值//參數數據類型:八大數據類型,String,枚舉,Class,注解類型,數組類型(12種)}通過接口自動生成Annotation的實現類
自定義注解,可以有參數,也可以沒有。沒有參數這個注解沒有意義
必須代碼解析注解它的功能,獲取該注解的對象,只能使用反射來獲取
創(chuàng)建一個類,在類中應用自定義的注解:
package AnnotationExample; //商品類 public class Good {@Role("管理員")public void shangjia(){System.out.println("商品正在上架");}@Role("管理員")public void xiajia(){System.out.println("商品正在下架");}public void show(){System.out.println("商品正在展示");}@Role("顧客")public void buy(){System.out.println("商品正在購買");} }創(chuàng)建一個注解:
package AnnotationExample; ? import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; ? //角色的注解 //如果參數名為value 在注解上 單獨給這個value參數賦值 省略 value= //如果給多個參數賦值,不能省略 @Target(ElementType.METHOD) //只能在方法上面使用 @Retention(RetentionPolicy.RUNTIME)//運行時 public @interface Role {// String role();//權限 管理員 顧客String value(); //String value() default ""; }創(chuàng)建一個工具類用來處理注解:
? package AnnotationExample; ? import java.lang.reflect.Method; import java.util.Scanner; ? public class TestGood {public static void main(String[] args) throws Exception {Scanner input = new Scanner(System.in);System.out.println("請輸入您的角色");String role = input.next();System.out.println("請輸入您要調用的方法");String methodName = input.next();Good good = new Good();//調用方法前 判斷角色與方法上定義的角色是否匹配//如果不匹配,禁止訪問//通過反射// 1、獲取Good的ClassClass<Good> clazz = Good.class;//2.獲取指定方法名的對象Method method = clazz.getDeclaredMethod(methodName);//獲取這個方法上需要的角色 ?if (method.isAnnotationPresent(Role.class)){ ?//判斷是否有@Role這個注解//獲取方法上的注解對象Role annotation = method.getAnnotation(Role.class);//獲取方法上的value參數String value = annotation.value();if (role.equals(value)){//判斷是否匹配System.out.println("您有權限");method.invoke(good); //調用方法}else{System.out.println("您沒有權限");}}else {//沒有 直接執(zhí)行System.out.println("沒有這個注解");} ? ? ? ?} }補 記憶版
內置注解:Java已經提供的注解,叫做內置注解。
| 注解名稱? | ? ?注解作用 |
| @Override | ?用于重寫方法上面,可以避免子類重寫方法時出錯。 |
| @Deprecated?? ? | 標識某個方法已經過時了,后續(xù)不推薦使用該方法(但是可以使用,只是不建議)。 |
| @SuppressWarnings?? | ?告訴編譯器忽略指定的警告信息(這樣代碼里面就看不見那些黃色波浪線了)。 |
| @FunctionalInterface?? | 標記某個接口是函數式接口(Jdk1.8新增)。 |
元注解:用于對其他注解進行解釋說明的,一般用于創(chuàng)建自定義注解時候,聲明自定義注解的一些信息,例如:注解作用范圍、注解能夠保存到哪個階段,注解是否需要包含到用戶文檔里面等等。
| 注解名稱 | 注解作用 |
| @Documented | 標著這個注解是否包含在用戶文檔中(即:javadoc文檔里面)。 |
| @Target? | ?標記這個注解能夠作用在哪些成員上面,例如:類上面、屬性上面、方法上面等等。 |
| @Retention | ?標記這個注解能夠保存到哪個階段,有三個可選值:源碼階段、字節(jié)碼階段、運行階段。 |
| @Inherited? | ?標記某個注解是繼承自哪個注解類(注解默認是不繼承任何類的)。 |
?? ?
?? ?
?
??
?
?
總結
- 上一篇: 【进大厂必学】3W字180张图学习Lin
- 下一篇: 升级打怪小游戏(面向对象)