Java注解和反射

注解和反射

1、什么是注解

  ①Annotation是从JDK5.0开始引入的新技术

  ②Annotation的作用

      1.不是程序本身,可以对程序作出解释

      2.可以被其他程序读取

  ③Annotation的格式—@注释名,例如@SuppressWarnings(value="unchecked")

  ④Annotation使用的地方

      可以附加在package、class、method、field等上面,相当于给他们添加了额外的辅助信息,可以通过反射机制编程实现对这些元数据的访问

 

2、内置注解

  ①@Override—定义在java.lang.Override中,表示方法被重写

  ②@Deprecated—定义在java.lang.Deprecated中,表示不鼓励程序员使用这样的元素

  ③@SuppressWarnings—定义在java.lang.SupressWarnings中,用来抑制编译时的警告信息

 

3、元注解

  ①元注解的作用是负责注解其他注解,Java定义了4个标准的meta—annotation类型,他们被用来提供对其他annotation类型作说明

  ②这些类型和它们所支持的类在java.lang.annotation包中可以找到

      1.@Target:用于描述注解的使用范围

      2.@Retention:表示需要在什么级别保存该注释信息

             用于描述注解的生命周期

               SOURCE<CLASS<RUNTIME

      3.@Document:说明该注解将被包含在javadoc中

      4.@Inherited:说明子类可以继承父类中的该注解

//定义一个注解
//Target 表示我们的注解可以用在哪些地方
//Retention 表示我们的注解在什么地方还有效
//Documented 表示是否将我们的注解生成在JavaDoc中
//Inherited 子类可以继承父类的注解
@Target(value = {ElementType.METHOD,ElementType.TYPE})
@Retention(value = RetentionPolicy.RUNTIME)
@Documented
@Inherited
@interface MyAnnotation{
​
}

 

4、自定义注解

  ①使用@interface自定义注解,自动继承了java.lang.annotation.Annotation接口

 1 public class Test3 {
 2  3     @MyAnnotation1(name="yq",id=1)
 4     public void test(){}
 5  6     //只有当参数只有一个,且参数名为value时,才可以省略赋值
 7     @MyAnnotation2("yq")
 8     public void test1(){}
 9 }
10 11 @Target({ElementType.METHOD,ElementType.TYPE})
12 @Retention(RetentionPolicy.RUNTIME)
13 @interface MyAnnotation1{
14     //注解的参数:参数类型 + 参数名();
15     String name() default "";//有默认值时可以不写参数;如果没有默认值,就必须给注解赋值
16     int id() default -1;//如果默认值为-1,代表不存在
17     String[] schools() default {"北大","清华","复旦"};
18 }
19 20 @Target({ElementType.METHOD,ElementType.TYPE})
21 @Retention(RetentionPolicy.RUNTIME)
22 @interface MyAnnotation2{
23     String value();
24 }

 

5、反射

  ①Reflection是Java被视为动态语言的关键,反射机制允许程序在执行期间借助于Reflection API取得任何类的内部信息,并能直接操作任意对象的内部属性及方法

            

 

6、获得反射对象

  通过getClass()方法返回一个Class,Class类是Java反射的源头,从程序运行角度看就是通过对象反射求出类的名称

 1 public class Test2 {
 2     public static void main(String[] args) throws ClassNotFoundException {
 3         //通过反射获取类的class对象
 4         Class c1=Class.forName("Annotation.User");
 5         System.out.println(c1);
 6         //一个类在内存中只有一个class对象
 7         //一个类被加载后,类的整个结构都会被封装在class对象中
 8         Class c2=Class.forName("Annotation.User");
 9         System.out.println(c1.hashCode());
10         System.out.println(c2.hashCode());
11     }
12 }
13 14 //实体类
15 class User{
16     private String name;
17     private int id;
18     private int age;
19 }

 

7、得到Class的方式

  ①Class类

      1.Class本身也是一个类

      2.Class对象只能由系统建立对象

      3.一个加载的类在JVM中只会有一个Class实例

      4.一个Class对象对应的是一个加载到JVM中的一个class文件

      5.每个类的实例都会记得自己是由哪个Class实例所生成

      6.通过Class可以完整地得到一个类中的所有被加载的结构

      7.Class类是Reflection的根源,针对任何你想动态加载、运行的类,唯有先获得相应的Class对象

  ②Class类的常用方法

      

  ③获取Class类的实例

        //方式一:通过对象获得
        Class c1=person.getClass();
​
        //方式二:forname获得
        Class c2=Class.forName("Annotation.Student");
​
        //方式三:通过类名.class获得
        Class c3=Student.class;
​
        //方式四:基本内置类型的包装类都有一个TYPE属性
        Class c4=Integer.TYPE;
​
        //获得父类类型
        Class c5=c1.getSuperclass();

 

8、有Class对象的类型

  ①class:外部类,成员(成员内部类,静态内部类),局部内部类,匿名内部类

  ②interface:接口

  ③[]:数组

  ④enum:枚举

  ⑤annotation:注解@interface

  ⑥primitive type:基本数据类型

  ⑦void

 1 public class Test5 {
 2     public static void main(String[] args) {
 3         Class c1=Object.class;//
 4         Class c2=Comparable.class;//接口
 5         Class c3=String[].class;//数组
 6         Class c4=int[][].class;//二维数组
 7         Class c5=Override.class;//注解
 8         Class c6= ElementType.class;//枚举
 9         Class c7=Integer.class;//基本类型
10         Class c8=void.class;//void
11         Class c9=Class.class;//Class类
12         System.out.println(c1);
13         System.out.println(c2);
14         System.out.println(c3);
15         System.out.println(c4);
16         System.out.println(c5);
17         System.out.println(c6);
18         System.out.println(c7);
19         System.out.println(c8);
20         System.out.println(c9);
21         //只要元素类型和维度一样,就是同一个Class
22         int[] a=new int[10];
23         int[] b=new int[100];
24         System.out.println(a.getClass().hashCode());
25         System.out.println(b.getClass().hashCode());
26     }
27 }

 

9、类加载分析

  ①类的加载过程

            

  ②类加载分析

 1 public class Test6 {
 2     public static void main(String[] args) {
 3         A a=new A();
 4         System.out.println(a.m);
 5     }
 6 }
 7  8 class A{
 9     static{
10         System.out.println("A类静态代码块初始化");
11         m=300;
12     }
13 14     static int m=100;
15 16     public A(){
17         System.out.println("A类的无参构造初始化");
18     }
19 }
20 /*
21 运行结果:
22 A类静态代码块初始化
23 A类的无参构造初始化
24 100
25 */

    1.加载到内存,会产生一个类对应的Class对象

    2.链接,链接结束后,m=0

    3.初始化,执行clinit方法

<clinit>(){
    System.out.println("A类静态代码块初始化");
    m=300;
    m=100;
}

      

 

10、分析类初始化

  ①类的主动引用(一定会发生类的初始化)

      1.当虚拟机启动,先初始化main方法所在的类

      2.new一个类的对象

      3.调用类的静态成员(除了final常量)和静态方法

      4.使用java.lang.reflect包的方法对类进行反射调用

      5.当初始化一个类,如果其父类没有被初始化,则先会初始化它的父类

  ②类的被动引用(不会发生类的初始化)

      1.当访问一个静态域时,只有真正声明这个域的类才会被初始化,例如当通过子类调用父类的静态变量,不会导致子类初始化

      2.通过数组定义类引用,不会触发此类的初始化

      3.引用常量不会触发此类的初始化(常量在链接阶段就存入调用类的常量池中了)

 

11、类加载器

  ①类加载器的作用

      1.将class文件字节码内容加载到内存中,并将这些静态数据转换成方法区的运行时数据结构,然后在堆中生成一个代表这个类的java.lang.Class对象,作为方法区中类数据的访问入口

      2.类缓存:标准的JavaSE类加载器可以按要求查找类,但一旦某个类被加载到加载器中,它将维持加载(缓存)一段时间。不过JVM垃圾回收机制可以回收这些Class对象

      

  ②类加载器类型

      

 1 public class Test7 {
 2     public static void main(String[] args) throws Exception {
 3         //获取系统类的加载器
 4         ClassLoader classLoader=ClassLoader.getSystemClassLoader();
 5         System.out.println(classLoader);
 6         //获取系统类加载器的父类加载器-->扩展类加载器
 7         ClassLoader parent=classLoader.getParent();
 8         System.out.println(parent);
 9         //获取扩展类加载器的父类加载器-->根加载器
10         ClassLoader parent1=parent.getParent();
11         System.out.println(parent1);
12         //测试当前类是哪个加载器加载的
13         ClassLoader classLoader1=Class.forName("Annotation.Test7").getClassLoader();
14         System.out.println(classLoader1);
15         //测试JDK内置的类是哪个加载器加载的
16         classLoader1=Class.forName("java.lang.Object").getClassLoader();
17         System.out.println(classLoader1);
18         //如何获得系统类加载器可以加载的路径
19         System.out.println(System.getProperty("java.class.path"));
20     }
21 }

 

  ③双亲委派机制

      当某个类加载器需要加载某个.class文件时,它首先把这个任务委托给他的上级类加载器,递归这个操作,如果上级的类加载器没有加载,自己才会去加载这个类。

 

12、获取类的运行时结构

  通过相关的方法获取相关的类信息

 1 public class Test8 {
 2     public static void main(String[] args) throws Exception {
 3         User user=new User("yq",1,6);
 4         Class c1=user.getClass();
 5         //获得类的名字
 6         System.out.println(c1.getName());//获得包名+类名
 7         System.out.println(c1.getSimpleName());//获得类名
 8         //获得类的属性
 9         Field[] fields=c1.getFields();//只能找到public属性
10         fields=c1.getDeclaredFields();//找到全部的属性
11         for(Field field:fields){
12             System.out.println(field);
13         }
14         //获得指定属性的值
15         Field name=c1.getDeclaredField("name");
16         System.out.println(name);
17         //获得类的方法
18         Method[] methods=c1.getMethods();//获得本类及其父类的全部public方法
19         for(Method method:methods){
20             System.out.println("getMethod---"+method);
21         }
22         methods=c1.getDeclaredMethods();//获得本类的所有方法
23         for(Method method:methods){
24             System.out.println("getDeclaredMethods---"+method);
25         }
26         //获得指定的方法
27         Method getName=c1.getMethod("getName",null);
28         Method setName=c1.getMethod("setName",String.class);
29         System.out.println(getName);
30         System.out.println(setName);
31         //获得类的构造器
32         Constructor[] constructors=c1.getConstructors();//获得全部的public构造器
33         for(Constructor constructor:constructors){
34             System.out.println("getConstructors---"+constructor);
35         }
36         constructors=c1.getDeclaredConstructors();//获得全部的构造器
37         for(Constructor constructor:constructors){
38             System.out.println("getDeclaredConstructors---"+constructor);
39         }
40         //获得指定的构造器
41         Constructor constructor=c1.getConstructor(String.class,int.class,int.class);
42         System.out.println(constructor);
43     }
44 }

 

13、动态创建对象

  通过反射实例化类,调用类的属性和方法

 1 public class Test9 {
 2     public static void main(String[] args) throws Exception {
 3         //获得Class对象
 4         Class c1=Class.forName("Annotation.User");
 5         //构造一个对象
 6         User user1=(User) c1.newInstance();//本质是调用了类的无参构造器
 7         System.out.println(user1);
 8         //通过构造器创建对象
 9         Constructor constructor=c1.getDeclaredConstructor(String.class,int.class,int.class);
10         User user2=(User) constructor.newInstance("yq",1,6);
11         System.out.println(user2);
12         //通过反射获取一个方法
13         Method setName=c1.getDeclaredMethod("setName",String.class);
14         setName.invoke(user1,"yq1");
15         System.out.println(user1.getName());
16         //通过反射操作属性
17         User user3=(User) c1.newInstance();
18         Field field=c1.getDeclaredField("name");//不能直接操作私有属性
19         field.setAccessible(true);//关闭程序的安全监测,使private修饰的也可以被操作
20         field.set(user3,"yq2");
21         System.out.println(user3.getName());
22     }
23 }

 

14、获取泛型信息

  通过相应的方法可以获得参数类型和返回值类型

 1 public class Test11 {
 2     public void test1(Map<String,User> map, List<User> list){
 3         System.out.println("test1");
 4     }
 5     public Map<String,User> test2(){
 6         System.out.println("test2");
 7         return null;
 8     }
 9 10     public static void main(String[] args) throws Exception {
11         Method method=Test11.class.getMethod("test1",Map.class,List.class);
12         Type[] types=method.getGenericParameterTypes();//获得泛型参数类型
13         for (Type type : types) {
14             System.out.println(type);
15             if (type instanceof ParameterizedType){//获取参数类型
16                 Type[] actualTypeArguments=((ParameterizedType)type).getActualTypeArguments();
17                 for (Type actualTypeArgument : actualTypeArguments) {
18                     System.out.println("---"+actualTypeArgument);
19                 }
20             }
21         }
22 23         method=Test11.class.getMethod("test2",null);
24         Type genericReturnType=method.getGenericReturnType();
25         if(genericReturnType instanceof ParameterizedType){
26             Type[] actualTypeArguments=((ParameterizedType)genericReturnType).getActualTypeArguments();
27             for (Type actualTypeArgument : actualTypeArguments) {
28                 System.out.println("-->"+actualTypeArgument);
29             }
30         }
31     }
32 }

 

15、获取注解信息

  通过相应的方法可以获取注解信息

 1 public class Test12 {
 2     public static void main(String[] args) throws Exception {
 3         Class c1=Class.forName("Annotation.Student1");
 4         //通过反射获得注解
 5         Annotation[] annotations=c1.getAnnotations();
 6         for (Annotation annotation : annotations) {
 7             System.out.println(annotation);
 8         }
 9         //获得注解的value值
10         TableStudent tableStudent=(TableStudent) c1.getAnnotation(TableStudent.class);
11         String value=tableStudent.value();
12         System.out.println(value);
13         //获得类指定注解
14         Field f=c1.getDeclaredField("name");
15         FieldStudent annotation=f.getAnnotation(FieldStudent.class);
16         System.out.println(annotation.colName()+";"+annotation.type()+";"+annotation.length());
17     }
18 }
19 20 @TableStudent("db_Student")
21 class Student1{
22     @FieldStudent(colName="db_name",type = "varchar",length = 10)
23     private String name;
24     @FieldStudent(colName="db_id",type = "int",length = 10)
25     private int id;
26     @FieldStudent(colName="db_age",type = "int",length = 6)
27     private int age;
28 29     public Student1() {
30     }
31 32     public Student1(String name, int id, int age) {
33         this.name = name;
34         this.id = id;
35         this.age = age;
36     }
37 38     public String getName() {
39         return name;
40     }
41 42     public void setName(String name) {
43         this.name = name;
44     }
45 46     public int getId() {
47         return id;
48     }
49 50     public void setId(int id) {
51         this.id = id;
52     }
53 54     public int getAge() {
55         return age;
56     }
57 58     public void setAge(int age) {
59         this.age = age;
60     }
61 62     @Override
63     public String toString() {
64         return "Student1{" +
65                 "name='" + name + '\'' +
66                 ", id=" + id +
67                 ", age=" + age +
68                 '}';
69     }
70 }
71 72 //类名的注解
73 @Target(ElementType.TYPE)
74 @Retention(RetentionPolicy.RUNTIME)
75 @interface TableStudent{
76     String value();
77 }
78 79 //属性的注解
80 @Target(ElementType.FIELD)
81 @Retention(RetentionPolicy.RUNTIME)
82 @interface FieldStudent{
83     String colName();
84     String type();
85     int length();
86 }

 

 

posted @ 2021-02-25 21:48  sumAll  阅读(100)  评论(0)    收藏  举报