zoukankan      html  css  js  c++  java
  • Java笔记:反射,注解

    一、反射

    1. 反射机制

    反射机制的相关类除了一个java.lang.Class,其余都在java.lang.reflect包下。
    反射机制用于读取class字节码文件,需要注意,JVM加载字节码到内存中时都只会保存一份,多次读取class文件时不用担心也会加载多次。
    反射机制相关的常用类:

    • java.lang.Class:代表整个类的字节码,表示一个类型。
    • java.lang.reflect.Method:代表字节码中的方法字节码,表示一个方法。
    • java.lang.reflect.Constructor:代表字节码中的构造方法字节码,表示一个构造方法。
    • java.lang.reflect.Field:代表字节码中的属性字节码,表示一个属性。

    2. 反射类字节码Class(类/类型)

    获取类的字节码(java.lang.Class类)有三种方式:

    • 第一种方式:通过Class类的静态方法forName,例如Class c1 = Class.forName("java.lang.String");就表示获取到了String这个类的class字节码,注意,这是Class类下的一个静态方法,参数需要是完整的包名。另外,Class.forName方法的使用会导致类的加载,也就是说如果希望只是执行一个类的静态代码块,并不执行其他的代码,就可以使用这个方法来进行类的加载,此时,自然就会去执行对应的静态代码了。
    • 第二种方式:通过Object类的getClass方法,例如String s = "abc"; Class c2 = s.getClass();,即通过任何类对象的getClass方法就可以拿到对应了类字节码了,并且因为JVM只会在内存中加载一份相同类的字节码,所以这个例子的c2和第一种方式的c1使用双等号判断返回结果是true。
    • 第三种方式:通过类的class属性,例如Class c3 = String.class;,java中任何类型都有class属性。

    Class中常用的方法:

    • String getName():返回类的完整类名(包含包路径)。
    • String getsimpleName():返回类的简类名(类定义名称)。
    • Field[] getFields():获取Class中所有public类型的Field对象(属性)。
    • Field[] getDeclaredFields():获取Class中所有的Field对象(属性)。
    • Field getDeclaredField(String name):获取指定名称的Field对象(属性)。
    • Method[] getDeclaredMethods():获取所有的Method对象(方法)。
    • Method getDeclaredMethod(String name, Class<?>... parameterTypes):根据方法名称和参数类型列表获取Method对象(方法),例如“userClass.getDeclaredMethod("login", String.class, int.class);”。
    • Constructor<?>[] getDeclaredConstructors():获取所有的Constructor对象(构造方法)。
    • Constructor<T> getDeclaredConstructor(Class<?>... parameterTypes):获取指定参数类型列表的Constructor对象(构造方法),例如“userClass.getDeclaredConstructor(String.class, int.class);”。
    • Class<? super T> getSuperclass():获取类的父类。
    • Class<?>[] getInterfaces():获取所有类实现的接口。

    3. 反射属性字节码Field(字段/属性)

    获取Field需要先获取到对应的类字节码Class,然后才能从类中获取到对应的Field(java.lang.reflect.Field)。
    Field常用方法:

    • Class<?> getType():返回属性的数据类型。
    • String getName():返回属性的名称。
    • int getModifiers():返回修饰符列表的代号,此代号可以使用java.lang.reflect.Modifier的静态方法toString方法传入代号获取到具体的修饰符名称列表。
    • void set(Object obj, Object value):给指定对象的Field对象赋予值value。
    • Object get(Object obj):获取指定对象的Field值(属性值)。
    • void setAccessible(boolean flag):设置为true时表示打破封装,如果不调用这个方法设置为true的话就没办法获取对象的私有属性了,调用这个方法之后就可以获取到所有的属性了,包括私有属性。

    4. 反射方法字节码Method(方法)

    获取Method需要先获取到对应的类字节码Class,然后才能从类中获取到对应的Method(java.lang.reflect.Method)。

    Method中的常用方法:

    • Class<?> getReturnType():获取返回值的数据类型。
    • Class<?>[] getParameterTypes():获取方法的参数类型列表。
    • int getModifiers():返回修饰符列表的代号,此代号可以使用java.lang.reflect.Modifier的静态方法toString方法传入代号获取到具体的修饰符名称列表。
    • Object invoke(Object obj, Object... args):调用指定对象的方法。

    5. 反射构造方法Constructor(构造方法)

    获取Constructor需要先获取到对应的类字节码Class,然后才能从类中获取到对应的Method(java.lang.reflect.Constructor)。

    Constructor中的常用方法:

    • int getModifiers():返回修饰符列表的代号,此代号可以使用java.lang.reflect.Modifier的静态方法toString方法传入代号获取到具体的修饰符名称列表。
    • T newInstance(Object... initargs):使用newInstance方法创建一个实例对象。

    二、注解

    1. 定义注解(Annotation)

    注解,或者称之为注释,也是一种引用数据类型,编译之后也会生成class文件,具体用法见示例:

    [修饰符列表] @interface 注解类型名{
        // 属性定义
    }

    注解定义示例:

    // 无属性的注解定义
    public @interface MyAnnotation{
        // 这里面什么都不写,表示没有属性
    }
    
    
    // 有属性的注解定义
    public @interface MyAnnotation2{
        // 定义一个没有默认值的属性,在使用这个注解的时候就必须给这个属性传值
        // 注意,注解的属性定义是有小括号的,但它不是方法,就只是属性
        String name();
        
        // 使用default给属性指定默认值,有默认值的属性在使用时就可以不用给这个属性传值了
        int id() default 2333;
    }
    
    
    // 属性只有一个,且为value时,使用时可以不用指定属性名称
    public @interface MyAnnotation3{
        String value();
    }

    注解使用示例:

    // 使用:直接在类、方法、属性、形参、注解等上面使用形如”@注解类型名“的格式即可。
    // 注解的使用其实就像修饰符一样在定义的前面加上就可以,但是通常的使用习惯是在定义上一行进行添加
    public class AnnotationTest {
        public static void main(String[] args) {
    
        }
    
        // 相当于:@MyAnnotation private int id;
        @MyAnnotation
        private int id;
    
        // 注解只有一个属性,且属性名为value时,可以不用指定属性名
        @MyAnnotation3("hello")
        public AnnotationTest() {
        }
    
        // 定义了没有默认值的属性的注解,就必须给这个属性传值,有默认值的属性可以传,也可以不传
        @MyAnnotation2(name = "zhangsan")
        public static void func() {
            @MyAnnotation2(name = "lisi", id = 666)
            int i = 10;
        }
    
        // 相当于:@MyAnnotation public void func2(@MyAnnotation String name)
        @MyAnnotation
        public void func2(@MyAnnotation String name) {
            System.out.println(name);
        }
    }

    注解属性类型:定义注解的属性时,属性的类型可以是byte、short、int、long、float、double、boolean、char、String、Class、枚举类型,以及这几种类型的数组形式,不能是其他的类型。有一个小技巧,属性如果是数组,并且使用时传入的数组元素只有一个的话,定义数组的大括号是可以不写的。

    2. Java内置注解

    内置注解在java.lang包下,常用的有:

    • @Override:这个注解只能注解方法,并且只是给编译器在编译阶段做参考用的,和运行阶段的代码没有关系,编译器在编译时会检查这个方法是否是重写的父类方法,如果不是则会报错。
    • @Deprecated:表示被标注的类、方法等元素已经过时了,不建议使用。在IDEA中,被标注的方法等会出现一条横线,提示你这个方法已过时。

    3. 元注解

    用来标注“注解类型”的注解,即注解的注解,称之为元注解,在java.lang.annotation包下。常用的元注解有:

    • @Target(ANNOTATION_TYPE):用来指定被标注的注解可以出现在哪些位置上,参数为枚举类型ElementType的数组,具体有哪些枚举值可以参考帮助文档,如“@Target(ElementType.METHOD)”表示被标注的注解只能出现在方法上。
    • @Retention(RUNTIME):用来指定被标注的注解最终保存在哪里,参数是一个枚举类型RetentionPolicy,有三个枚举值,“@Retention(RetentionPolicy.SOURCE)”表示被标注的注解保存在java源文件中,并不会出现在编译之后的class文件中,“@Retention(RetentionPolicy.CLASS)”表示被标注的注解保存在class文件中,“@Retention(RetentionPolicy.RUNTIME)”表示被标注的注解保存在class文件中,并且可以被反射机制读取出来。

    4. 反射注解

    以类的注解为例,首先获取到类的字节码对象后,使用Class对象的方法进行反射,常用的方法有:

    • boolean isAnnotationPresent(MyAnnotation.class):判断一个类是否有指定的注解,这里需要传入一个指定注解的类字节码对象。
    • getAnnotation(MyAnnotation.class):获取类的指定注解对象,这里需要传入一个指定注解的类字节码对象。

    属性获取:通过反射拿到注解对象之后,就可以通过调用方法(其实是属性)的形式获取属性值,因为注解定义属性时,本身就自带小括号,所以看起来就是在调用方法了,如“String name = annotationObj.name();”
    注:方法、属性等的注解获取也是和上面的方法一样,而且调用的方法等大多也都是一样的。

    5. 注解的作用

    注解通常是通过反射机制去检查被注解的类、方法等是否满足要求,比如@Override就是检查被注解的方法是否是重写父类的方法,如果不是就会编译报错。

  • 相关阅读:
    React简明学习
    react-router简明学习
    react组件生命周期
    在vue中使用css modules替代scroped
    深入理解javascript中的事件循环event-loop
    javascript中的内存管理和垃圾回收
    移动端中的陀螺仪
    基于create-react-app的再配置
    vscode常用设置
    更高效地使用搜索引擎
  • 原文地址:https://www.cnblogs.com/guyuyun/p/13193546.html
Copyright © 2011-2022 走看看