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