Java注解与反射

Java注解与反射1 注解1.1 内置注解1.2 元注解1.3 自定义注解2 反射机制2.1 获取反射对象2.2 类加载的内存分析2.3 类初始化条件2.4 类加载器2.5 获取运行时类的信息2.6 动态创建对象2.7 反射获取泛型2.8 反射获取注解
Java注解与反射
1 注解
Annotation的作用:
- 不是程序,但是是对程序做解释(与注释相同)
- 可以被其他程序读取
Annotation的格式:
- @注解(valuse="")
1.1 内置注解
- @Override 只能用于修饰方法,表示此方法重写父类的方法
- @Deprecated 已过时,提示此方法有更好的替代方法,建议使用替代的方法
- @SuppressWarnings 镇压警告,抑制编译时产生的警告信息
xxxxxxxxxx251/*内置注解*/2public class TestAnnotation01 {3
4    /*重写注解*/5    6    public String toString() {7        return super.toString();8    }9
10    /*废弃 已过时*/11    12    public static void test(){13        System.out.println("Deprecated");14    }15
16    /*镇压警告*/17    ("all")18    public static void warn(){19        List<String> list = new ArrayList<String>();20    }21
22    public static void main(String[] args) {23     test();24    }25}1.2 元注解
元注解的作用是注解其他的注解
- @Target:表示注解的使用范围(方法,类...)
- @Retention:表示在什么级别保存注解信息(SOURCE CLASS RUNTIME)
- @Documented:表示将注解生成在JAVAdoc中
- @Inherited:表示子类可以继承父类的注解
xxxxxxxxxx241/*测试元注解*/2public class TestAnnotation02 {3
4    5    public void test(){6
7    }8}9
10/*定义一个注解*/11//Target 表示注解可以用的位置12(value = ElementType.METHOD)13
14//Retention 表示注解在什么时候有效15(value = RetentionPolicy.RUNTIME)16
17//Documented 表示将注解生成在JAVAdoc中18
20//Inherited 表示子类可以继承父类的注解21@interface MyAnnotation{23
24}1.3 自定义注解
参数为value可以省略参数名
xxxxxxxxxx421/*自定义注解*/2public class TestAnnotation03 {3
4    (name = "cr", age = 18, schools = {"nm","sm"})5    public void test() {6
7    }8
9    ("pl")10    public void test2() {11
12    }13}14
15/*定义一个注解*/16//Target 表示注解可以用的位置17(value = {ElementType.METHOD,ElementType.TYPE})18
19//Retention 表示注解在什么时候有效20(value = RetentionPolicy.RUNTIME)21
22//Documented 表示将注解生成在JAVA doc中23
25//Inherited 表示子类可以继承父类的注解26@interface AnnotationTest{28
29    //注解的参数: 参数类型 + 参数名()30    String name() default "";31    int age() default 0;32    int id() default -1;//默认值为-1,代表不存在33
34    String[] schools();35}36
37
38(value = {ElementType.METHOD,ElementType.TYPE})39(value = RetentionPolicy.RUNTIME)40@interface AnnotationTest02 {41    String value();42}2 反射机制
动态语言&静态语言
- 动态语言:在运行时可以改变其结构的语言 - C#,JavaScript,PHP,Python
 
- 静态语言:运行时结构不能改变 - Java,c,c++
 
- Java是准动态语言,可以通过反射机制实现动态语言的特性 
2.1 获取反射对象
Reflection
- 反射机制允许程序在执行时,获取任何类的内部信息,并能直接操作任意内部属性及方法(动态的特性)
- 加载完类后,在堆方法区中就产生了Class类的对象,Class对象包含了所有类的结构信息
获取class对象:
定义需要获取反射对象的类:
xxxxxxxxxx551/*实体类:pojo entity*/2class User{3    private String name;4    private int id;5    private int age;6
7    public User() {8    }9
10    public User(String name, int id, int age) {11        this.name = name;12        this.id = id;13        this.age = age;14    }15
16    public void setName(String name) {17        this.name = name;18    }19
20    public void setId(int id) {21        this.id = id;22    }23
24    public void setAge(int age) {25        this.age = age;26    }27
28    public String getName() {29        return name;30    }31
32    public int getId() {33        return id;34    }35
36    public int getAge() {37        return age;38    }39
40    41    public String toString() {42        return "User{" +43                "name='" + name + '\'' +44                ", id=" + id +45                ", age=" + age +46                '}';47    }48}49
50class Student extends User{51
52    public Student(int id, int age) {53        super("学生", id, age);54    }55}测试反射获取class对象:
xxxxxxxxxx371public static void main(String[] args) throws ClassNotFoundException {2    /*通过反射获取类的Class对象*/3    Class c1 = Class.forName("Demo03.User");4    System.out.println(c1);5
6    Class c2 = Class.forName("Demo03.User");7
8    /*一个类在内存中只有一个Class对象9    * 一个类被加载之后,类的整个结构都会封装在Class对象中*/10    System.out.println(c1.hashCode());11    System.out.println(c2.hashCode());12    //同一个对象13    System.out.println("----------------");14
15    User user = new Student(1,1);16    System.out.println("人名是:"+user.getName());17
18    /*1.通过对象获得Class对象*/19    Class c3 = user.getClass();20    System.out.println(c3.hashCode());21
22    /*2.通过forname获取Class*/23    Class c4 = Class.forName("Demo03.Student");24    System.out.println(c4.hashCode());25
26    /*3.通过类名.class获得*/27    Class c5 = Student.class;28    System.out.println(c5.hashCode());29
30    /*4.基本内置类的包装类都有Type属性*/31    Class c6 = Integer.TYPE;32    System.out.println(c6.hashCode());33
34    /*获得父类类型*/35    Class c7 = c3.getSuperclass();36    System.out.println(c7);37}获取各种类型的Class对象
xxxxxxxxxx91Class c1 = Object.class;      //类2Class c2 = Comparable.class;  //接口3Class c3 = String[].class;    //一维数组4Class c4 = int[][].class;     //二维数组5Class c5 = Integer.class;     //基本数据类型6Class c6 = Override.class;    //注解7Class c7 = ElementType.class; //枚举8Class c8 = void.class;        //void9Class c9 = Class.class;       //Classxxxxxxxxxx91class java.lang.Object2interface java.lang.Comparable3class [Ljava.lang.String;4class [[I5class java.lang.Integer6interface java.lang.Override7class java.lang.annotation.ElementType8void9class java.lang.Class2.2 类加载的内存分析
Java内存
- 堆区: - new的对象,数组
- 可以被所有的线程共享
- 不会存放引用
 
- 栈区: - 存放局部变量
- 引用对象的变量(引用在堆区的地址)
 
- 方法区: - 包含所有的class
- 可以被所有的线程共享
- 特殊的堆区
 
类的加载过程
- 1.类的加载:将类的class文件读入内存,并为之创建一个Class对象,此过程由类加载器完成 
- 2.类的链接:将类的二进制数据合并到JRE中 - 验证:确保类的信息符合JVM规范
- 准备:为static变量分配内存,并设置默认值,在方法区中
- 解析:将常量池的符号引用(常量名)替换为直接引用(地址)
 
- 3.类的初始化:JVM负责类初始化 - 执行类构造器方法,类构造器自动收集所有变量的赋值和静态代码块中的语句合并(不是对象构造器)
- 初始化一个类的时候,如果发现父类没有初始化,会先将父类进行初始化
- JVM保证每个类的类构造器方法在多线程环境正确加锁和同步
 
测试类的加载:
xxxxxxxxxx181class A{2    static {3        System.out.println("A类静态代码块");4        m = 300;5    }6
7    static int m = 100;8
9    public A() {10        System.out.println("A类无参构造器");11    }12}13
14 public static void main(String[] args) {15        System.out.println("创建A类的对象");16        A a = new A();17        System.out.println(A.m);18 }执行结果:
- 创建A类的对象 A类静态代码块 A类无参构造器 100
类的加载过程:
- 1.加载到内存,产生一个A类对应的Class对象 
- 2.链接,链接结束后 m=0 
- 3.初始化,类构造器方法将静态代码块合并,结果: - <clinit>(){ - System.out.println("A类静态代码块");  m = 300;  m = 100; - } 
 
2.3 类初始化条件
类主动引用(发生类初始化)
- JVM启动,初始化main方法所在的类
- new一个类的对象
- 调用类的静态成员变量或静态方法
- 使用反射方式对类进行反射调用
- 初始化一个类会先初始化它的父类
类的被动引用(不发生类的初始化)
- 访问一个静态作用域,只有声明这个域的类会被初始化(子类用父类的静态方法,子类不会初始化)
- 通过数组定义引用,不会触发类初始化
- 引用常量不会触发类初始化(链接阶段已经进入常量池)
测试类的初始化:
xxxxxxxxxx421/*测试类何时初始化*/2public class TestClassInit {3    static {4        System.out.println("Main类被加载");5    }6
7    public static void main(String[] args) throws ClassNotFoundException {8        /*主动引用*/9        /*new*/10        //Son son = new Son();11
12        /*反射*/13        //Class.forName("Demo04.Son");14
15        /*通过子类调用父类的静态不会加载子类*/16        //System.out.println(Son.b);17
18        /*通过数组定义引用,不会发生类的初始化*/19        //Son[] array = new Son[5];20
21        /*使用常量不会发生类初始化*/22        System.out.println(Son.n);23    }24}25
26class Father{27    static int b = 2;28
29    static {30        System.out.println("父类被加载");31    }32}33
34class Son extends Father{35    static {36        System.out.println("子类被加载");37        m = 300;38    }39
40    static int m = 100;41    static final int n = 1;42}2.4 类加载器
- 类加载器的作用:将class文件字节码加载到内存中,将静态数据转换成方法区的运行时数据结构,在堆区生成Java.lang.Class对象,作为方法区中类数据的访问入口
- 类缓存:某个类加载到类加载器中,会维持加载一段时间,JVM垃圾回收机制会回收Class对象
类加载器种类
- 引导类加载器:JVM自带类加载器,装载核心类库,C++编写,无法直接获取
- 扩展类加载器:负责jre/lib/ext目录下的jar包或指定目录下的jar包装入工作库
- 系统类加载器:负责java -class path或指定目录jar包装入,最常用类加载器
xxxxxxxxxx281public static void main(String[] args) throws ClassNotFoundException {2
3    /*获取系统类加载器*/4    ClassLoader systemClassLoader = ClassLoader.getSystemClassLoader();5    System.out.println(systemClassLoader);6
7    /*获取系统类加载器的父类加载器-->扩展类加载器*/8    ClassLoader extendClassLoader = systemClassLoader.getParent();9    System.out.println(extendClassLoader);10
11    /*获取扩展类加载器的父类加载器-->根加载器*/12    ClassLoader rootClassLoader = extendClassLoader.getParent();13    System.out.println(rootClassLoader);14
15    /*获取当前类的类加载器*/16    ClassLoader classLoader = Class.forName("Demo04.TestClassLoader").getClassLoader();17    System.out.println(classLoader);18
19    /*测试JDK内部类的类加载器*/20    classLoader = Class.forName("java.lang.Object").getClassLoader();21    System.out.println(classLoader);22
23    /*类加载器可以加载的路径*/24    System.out.println(System.getProperty("java.class.path"));25
26    /*双亲委派机制*/27    //保证用户定义的包不会影响java内部类28}2.5 获取运行时类的信息
xxxxxxxxxx631/*获取类运行时结构*/2public class GetClassInformation {3    public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException, NoSuchMethodException {4        Class c1 = Class.forName("Demo03.User");5
6        System.out.println("名字:");7        /*获得类的名字*/8        System.out.println(c1.getName());9        System.out.println(c1.getSimpleName());10
11        System.out.println("属性:");12        /*获得类的所有属性*/13        //Field[] fields = c1.getFields();         //只能找到public属性14        Field[] fields = c1.getDeclaredFields();   //找到全部属性15        for (Field field : fields) {16            System.out.println(field);17        }18
19        System.out.println("---------------");20        /*获得指定属性*/21        Field name = c1.getDeclaredField("name");22        System.out.println(name);23
24        System.out.println("方法:");25        /*获取类的方法*/26        Method[] methods = c1.getMethods();//获取本类与父类所有public方法27        for (Method method : methods) {28            System.out.println(method);29        }30
31        System.out.println("---------------");32        methods = c1.getDeclaredMethods();//获取本类的所有方法33        for (Method method : methods) {34            System.out.println(method);35        }36
37        /*获取指定方法*/38        System.out.println("---------------");39        Method getName = c1.getMethod("getName",null);40        Method setName = c1.getMethod("setName", String.class);41
42        System.out.println(getName);43        System.out.println(setName);44
45        System.out.println("构造器:");46        /*获取类的构造器*/47        Constructor[] constructors = c1.getConstructors();48        for (Constructor constructor : constructors) {49            System.out.println(constructor);50        }51
52        System.out.println("---------------");53        constructors = c1.getDeclaredConstructors();54        for (Constructor constructor : constructors) {55            System.out.println(constructor);56        }57
58        /*获取指定构造器*/59        System.out.println("---------------");60        Constructor constructor = c1.getConstructor(String.class,int.class,int.class);61        System.out.println(constructor);62    }63}2.6 动态创建对象
xxxxxxxxxx301/*动态创建对象*/2public class TestDynClassCreate {3    public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException, NoSuchFieldException {4        /*获得class对象*/5        Class class1 = Class.forName("Demo05.User");6
7        /*构造一个对象*/8        Object user = class1.newInstance();//本质调用无参构造器9        System.out.println(user);10
11        /*通过构造器创建对象*/12        Constructor constructor = class1.getDeclaredConstructor(String.class,int.class,int.class);13        Object user1 = constructor.newInstance("张三", 1, 18);14        System.out.println(user1);15
16        /*通过反射获取一个方法*/17        User user2 = (User) class1.newInstance();18        Method setName = class1.getMethod("setName", String.class);19        setName.invoke(user2,"李明");//激活 传递对象和参数20        System.out.println(user2.getName());21
22        /*通过反射操作属性*/23        User user3 = (User) class1.newInstance();24        Field name = class1.getDeclaredField("name");25
26        name.setAccessible(true);//关闭访问安全检测27        name.set(user3,"李华");28        System.out.println(user3.getName());29    }30}2.7 反射获取泛型
xxxxxxxxxx491/*测试反射获取泛型*/2public class TestGetParadigm {3
4    public void test01(Map<String,User> map, List<User> list){5        System.out.println("test 1");6    }7
8    public Map<String,User> test02(){9        System.out.println("test 2");10        return null;11    }12
13    public static void main(String[] args) throws NoSuchMethodException {14        Method test01 = TestGetParadigm.class.getMethod("test01", Map.class, List.class);15
16        /*获取泛型的参数类型*/17        Type[] genericParameterTypes = test01.getGenericParameterTypes();18
19
20        for (Type genericParameterType : genericParameterTypes) {21            System.out.println("#"+genericParameterType);22            /*泛型的参数类型是否为结构化参数类型*/23            if (genericParameterType instanceof ParameterizedType){24                /*转泛型参数类型为结构化参数类型,并调用获取真实参数信息*/25                Type[] actualTypeArguments = ((ParameterizedType) genericParameterType).getActualTypeArguments();26                for (Type actualTypeArgument : actualTypeArguments) {27                    System.out.println(actualTypeArgument);28                }29            }30        }31
32        System.out.println("------------");33
34        Method test02 = TestGetParadigm.class.getMethod("test02", null);35
36        /*获取泛型的参数类型*/37        Type genericReturnType = test02.getGenericReturnType();38
39        System.out.println("#"+genericReturnType);40        /*泛型的参数类型是否为结构化参数类型*/41        if (genericReturnType instanceof ParameterizedType){42            /*转泛型参数类型为结构化参数类型,并调用获取真实参数信息*/43            Type[] actualTypeArguments = ((ParameterizedType) genericReturnType).getActualTypeArguments();44            for (Type actualTypeArgument : actualTypeArguments) {45                System.out.println(actualTypeArgument);46            }47        }48    }49}2.8 反射获取注解
x
1/*获取注解信息*/2public class TestGetAnnotations {3    public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException {4        Class c1 = Class.forName("Demo05.Student");5
6        /*获得注解*/7        Annotation[] annotations = c1.getAnnotations();8        for (Annotation annotation : annotations) {9            System.out.println(annotation);10        }11
12        /*获得注解的值*/13        Table table = (Table) c1.getAnnotation(Table.class);14        String value = table.value();15        System.out.println(value);16
17        /*获得类指定注解值*/18        Field field = c1.getDeclaredField("name");19        FieldDb annotation = field.getAnnotation(FieldDb.class);20        System.out.println(annotation.columName());21        System.out.println(annotation.type());22        System.out.println(annotation.length());23
24    }25}26
27("student")28class Student{29    (columName = "db_id", type = "int", length = 10)30    private int id;31    (columName = "db_age", type = "int", length = 10)32    private int age;33    (columName = "db_name", type = "varchar", length = 32)34    private String name;35
36    public Student() {37    }38
39    public Student(int id, int age, String name) {40        this.id = id;41        this.age = age;42        this.name = name;43    }44
45    public int getAge() {46        return age;47    }48
49    public int getId() {50        return id;51    }52
53    public String getName() {54        return name;55    }56
57    public void setId(int id) {58        this.id = id;59    }60
61    public void setAge(int age) {62        this.age = age;63    }64
65    public void setName(String name) {66        this.name = name;67    }68}69
70/*类名的注解*/71(ElementType.TYPE)72(RetentionPolicy.RUNTIME)73@interface Table{74    String value();75}76
77/*属性的注解*/78(ElementType.FIELD)79(RetentionPolicy.RUNTIME)80@interface FieldDb{81    String columName();82    String type();83    int length();84}posted on 2021-12-02 17:48 Egoistic_Flowers 阅读(44) 评论(0) 收藏 举报
 
 
         
                
            
         浙公网安备 33010602011771号
浙公网安备 33010602011771号