Java面向对象编程篇6——注解与反射
Java面向對象編程篇6——注解與反射
1、注解概述
Java 注解(Annotation)又稱 Java 標注,是 JDK5.0 引入的一種注釋機制
Java 語言中的類、方法、變量、參數和包等都可以被標注。Java 標注可以通過反射獲取標注內容。在編譯器生成類文件時,標注可以被嵌入到字節碼中。Java 虛擬機可以保留標注內容,在運行時可以獲取到標注內容 。 當然它也支持自定義 Java 標
可簡單理解為標簽
2、元注解
元注解顧名思義我們可以理解為注解的注解
@Retention(注解保留時期)
-
@Retention(RetentionPolicy.SOURCE),注解僅存在于源碼中,在class字節碼文件中不包含
-
@Retention(RetentionPolicy.CLASS), 默認的保留策略,注解會在class字節碼文件中存在,但運行時無法獲得
-
@Retention(RetentionPolicy.RUNTIME), 注解會在class字節碼文件中存在,在運行時可以通過反射獲取到
@Target(注解作用的范圍)
- @Target(ElementType.TYPE) 作用接口、類、枚舉、注解
- @Target(ElementType.FIELD) 作用屬性字段、枚舉的常量
- @Target(ElementType.METHOD) 作用方法
- @Target(ElementType.PARAMETER) 作用方法參數
- @Target(ElementType.CONSTRUCTOR) 作用構造函數
- @Target(ElementType.LOCAL_VARIABLE)作用局部變量
- @Target(ElementType.ANNOTATION_TYPE)作用于注解(@Retention注解中就使用該屬性)
- @Target(ElementType.PACKAGE) 作用于包
- @Target(ElementType.TYPE_PARAMETER) 作用于類型泛型,即泛型方法、泛型類、泛型接口 (jdk1.8加入)
- @Target(ElementType.TYPE_USE) 類型使用.可以用于標注任意類型除了 class (jdk1.8加入)
@Documented(文檔)
- Document的英文意思是文檔。它的作用是能夠將注解中的元素包含到 Javadoc 中去
@Inherited(繼承)
- Inherited的英文意思是繼承
- 并不是說注解本身可以繼承,而是說如果一個超類被 @Inherited 注解過的注解進行注解的話,那么如果它的子類沒有被任何注解應用的話,那么這個子類就繼承了超類的注解
注解 MyAnnotation被 @Inherited 修飾,之后類 Test 被 MyAnnotation 注解,類 Test1 繼承 Test,那么類 Test1 也擁有 MyAnnotation 這個注解。
@Repeatable(可重復)
- Repeatable的英文意思是可重復的。顧名思義說明被這個元注解修飾的注解可以同時作用一個對象多次,但是每次作用注解又可以代表不同的含義
-
在注解中定義屬性時它的類型必須是 8 種基本數據類型外加 類、接口、注解及它們的數組
-
注解中屬性可以有默認值,默認值需要用 default 關鍵值指定
-
如果一個注解內僅僅只有一個名字為 value 的屬性時,應用這個注解時可以直接接屬性值填寫到括號內
3、注解的提取(反射)
這里我們暫時先使用以下反射,稍后詳細講述反射
@Retention(RetentionPolicy.RUNTIME) public @interface Values {Value[] value(); } @Retention(RetentionPolicy.RUNTIME) @Repeatable(Values.class) public @interface Value {String id() default "id";String name() default "name"; } @Value(id = "1",name = "zhangsan") @Value(id = "2",name = "lisi") public class Test {public static void main(String[] args) {if (Test.class.isAnnotationPresent(Values.class)){Values annotation = Test.class.getAnnotation(Values.class);Value[] values = annotation.value();for (Value value : values) {System.out.println("id="+value.id());System.out.println("name="+value.name());}}} } id=1 name=zhangsan id=2 name=lisi屬性、方法上的注解照樣是可以的,同樣還是要假手于反射
@Retention(RetentionPolicy.RUNTIME) public @interface Values {Value[] value(); } @Retention(RetentionPolicy.RUNTIME) @Repeatable(Values.class) public @interface Value {String id() default "id";String name() default "name"; } import java.lang.reflect.Field; import java.lang.reflect.Method; @Value(id = "-1",name = "yoya") @Value(id = "0",name = "ruoye") public class Test {@Value(id = "1",name = "zhangsan")public int a;@Value(id = "2",name = "lisi")public void todo(){}public static void main(String[] args) {boolean hasAnnotation = Test.class.isAnnotationPresent(Values.class);if ( hasAnnotation ) {Values values = Test.class.getAnnotation(Values.class);//獲取類的注解System.out.println("類注解======================");System.out.println(values);}try {Field a = Test.class.getDeclaredField("a");a.setAccessible(true);//獲取一個成員變量上的注解Value value = a.getAnnotation(Value.class);if ( value != null ) {System.out.println("屬性注解======================");System.out.println(value.id());System.out.println(value.name());}Method testMethod = Test.class.getDeclaredMethod("todo");if (testMethod!=null) {// 獲取方法中的注解System.out.println("方法注解======================");Value declaredAnnotation = testMethod.getDeclaredAnnotation(Value.class);if ( value != null ){System.out.println(declaredAnnotation.id());System.out.println(declaredAnnotation.name());}}} catch (Exception e) {System.out.println(e.getMessage());}} }4、反射(框架設計的靈魂)
4.1、反射是什么
-
將類的各個組成部分封裝為其他對象,這就是反射機制
-
可以在程序運行過程中,操作這些對象
-
可以解耦,提高程序的可擴展性
-
過多的反射會影響性能
4.2、獲取Class對象的三種方式
同一個字節碼文件(*.class)在一次程序運行過程中,只會被加載一次,不論通過哪一種方式獲取的Class對象都是同一個
4.2.1、通過該類的對象去獲取到對應的Class對象
一般不使用這種方式
public class Student { } public class Test {public static void main(String[] args) {Student student = new Student();System.out.println(student.getClass());System.out.println(student.getClass().getName());} } class com.ruoye.Student com.ruoye.Student4.2.2、通過類名.class靜態屬性獲取
需要導包
public class Student { } public class Test {public static void main(String[] args) {System.out.println(Student.class);} } class com.ruoye.Student4.2.3、通過Class類中的靜態方法 forName()方法獲取
public class Student { } public class Test {public static void main(String[] args) throws ClassNotFoundException {Class<Student> studentClass = (Class<Student>) Class.forName("com.ruoye.Student");System.out.println(studentClass.getName());} } com.ruoye.Student4.3、通過Class對象獲取到該類的構造器
public class Student {private int num;private String name;public Student() {}private Student(int num) {this.num = num;}public Student(String name) {this.name = name;}private Student(int num, String name) {this.num = num;this.name = name;} } public class Test {public static void main(String[] args) throws NoSuchMethodException {Class<Student> studentClass = Student.class;System.out.println("所有構造函數================");Constructor<?>[] declaredConstructors = studentClass.getDeclaredConstructors();for (Constructor<?> declaredConstructor : declaredConstructors) {System.out.println(declaredConstructor);}System.out.println("公有構造函數=================");Constructor<?>[] constructors = studentClass.getConstructors();for (Constructor<?> constructor : constructors) {System.out.println(constructor);}System.out.println("指定參數的所有構造器==============");Constructor<Student> constructor = studentClass.getDeclaredConstructor(int.class);System.out.println(constructor);System.out.println("指定參數的公開構造器==============");Constructor<Student> constructor1 = studentClass.getConstructor(String.class);System.out.println(constructor1);} } 所有構造函數================ private com.ruoye.Student(int,java.lang.String) public com.ruoye.Student(java.lang.String) private com.ruoye.Student(int) public com.ruoye.Student() 公有構造函數================= public com.ruoye.Student(java.lang.String) public com.ruoye.Student() 指定參數的所有構造器============== private com.ruoye.Student(int) 指定參數的公開構造器============== public com.ruoye.Student(java.lang.String)4.4、通過獲取到的構造器創建對象
public class Student {private int num;private String name;public Student() {}private Student(int num) {this.num = num;}public Student(String name) {this.name = name;}private Student(int num, String name) {this.num = num;this.name = name;}@Overridepublic String toString() {return "Student{" +"num=" + num +", name='" + name + '\'' +'}';} } public class Test {public static void main(String[] args) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {Class<Student> studentClass = Student.class;Constructor<Student> declaredConstructor = studentClass.getDeclaredConstructor(int.class, String.class);//暴力反射declaredConstructor.setAccessible(true);Student zhangsan = declaredConstructor.newInstance(1, "zhangsan");System.out.println(zhangsan);} }4.5、通過Class對象獲取成員變量
public class Student {public boolean flag;private int num;private String name;public Student() {}private Student(int num) {this.num = num;}public Student(String name) {this.name = name;}private Student(int num, String name) {this.num = num;this.name = name;}public boolean isFlag() {return flag;}public void setFlag(boolean flag) {this.flag = flag;}public int getNum() {return num;}public void setNum(int num) {this.num = num;}public String getName() {return name;}public void setName(String name) {this.name = name;}@Overridepublic String toString() {return "Student{" +"num=" + num +", name='" + name + '\'' +'}';} } public class Test {public static void main(String[] args) throws NoSuchFieldException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {Class<Student> studentClass = Student.class;System.out.println("獲取所有字段==============");Field[] fields = studentClass.getDeclaredFields();for (Field field : fields) {System.out.println(field.getName());}System.out.println("獲取公有字段==============");Field[] fields1 = studentClass.getFields();for (Field field : fields1) {System.out.println(field.getName());}System.out.println("獲取特定字段===========");Field num = studentClass.getDeclaredField("num");System.out.println(num.getName());System.out.println("為字段設置值============");Student student = studentClass.getDeclaredConstructor(null).newInstance();student.setName("ruoye");System.out.println(student.toString());} }4.6、通過Class對象獲取到該類的方法
public class Student {private void sleep(int a){System.out.println("sleep");}public void study(String name){System.out.println("study");} } public class Test {public static void main(String[] args) throws NoSuchFieldException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {Class<Student> studentClass = Student.class;System.out.println("獲取所有方法================");Method[] declaredMethods = studentClass.getDeclaredMethods();for (Method declaredMethod : declaredMethods) {System.out.println(declaredMethod);}System.out.println("獲取公有方法(包含父類的方法)================");Method[] declaredMethods1 = studentClass.getMethods();for (Method declaredMethod : declaredMethods1) {System.out.println(declaredMethod);}System.out.println("獲取指定公共方法================");Method study = studentClass.getMethod("study", String.class);System.out.println(study);System.out.println("獲取指定方法================");Method sleep = studentClass.getDeclaredMethod("sleep", int.class);Student student = studentClass.getDeclaredConstructor(null).newInstance();sleep.setAccessible(true);System.out.println(sleep);//喚醒方法sleep.invoke(student,1);} }4.7、通過Method對象調用指定方法
public class Student {private void sleep(int a){System.out.println("sleep:"+a);}public void study(String name){System.out.println(name+":study");}public static void run(String name){System.out.println(name+":run");} } public class Test {public static void main(String[] args) throws NoSuchFieldException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {Class<Student> studentClass = Student.class;Method sleep = studentClass.getDeclaredMethod("sleep", int.class);Student student = studentClass.getDeclaredConstructor(null).newInstance();sleep.setAccessible(true);System.out.println(sleep);sleep.invoke(student,1);Method run = studentClass.getDeclaredMethod("run", String.class);System.out.println(run);//方法是靜態的,那么可以忽略指定的 obj 參數。該參數可以為 null//方法所需的形參數為 0,則所提供的 args 數組長度可以為 0 或 null//方法是靜態的,并且尚未初始化聲明此方法的類,則會將其初始化run.invoke(null,"zhangsan");} }總結
以上是生活随笔為你收集整理的Java面向对象编程篇6——注解与反射的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: linux如何把mysql表名换成小写_
- 下一篇: jpa取出mysql数组_java读取数