注解 Annotation

  • 本质是一个接口,继承 java.lang.annotation.Annotation 接口;

    • 注解的属性就是接口中的抽象方法;
    • 可以使用 default 给属性赋默认值;
    // @Override 注解
    @Target(ElementType.METHOD)
    @Retention(RetentionPolicy.SOURCE)
    public @interface Override {
    }
    // @SuppressWarnings 注解
    @Target({TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE})
    @Retention(RetentionPolicy.SOURCE)
    public @interface SuppressWarnings {
        String[] value();
    }
    // 自定义注解
    元注解
    public @interface 注解名称{
        属性列表 default "xxx";
    }
  • 元注解: 描述注解的注解:

    • @Target 声明注解的位置,属性 ElementType
      • TYPE:类与接口上;
      • FIELD:成员变量上;
      • METHOD:方法体上;
      • PARAMETER:方法参数上;
      • ……
    • @Retention 声明注解将被保留的阶段,属性 RetentionPolicy
      • SOURCE:只保留在源文件,编译成 class 文件时就不再存在;
        • 检查性作用,@Override、@SuppressWarning
      • CLASS(默认):保留到 class 文件,加载 class 时遗弃;
        • 编译期生成辅助性代码,@Lombok
      • RUNTIME:保存到 class 文件中,随 class 文件一起被加载进 JVM;
        • 运行时获取(通过反射)
    • @Inherited 声明注解是否被子类继承;
  • 反射获取运行时注解:

    @Target(ElementType.TYPE)
    @Retention(RetentionPolicy.RUNTIME)
    @interface ClassInfo {
        String value();
    }
     
    @Target(ElementType.FIELD)
    @Retention(RetentionPolicy.RUNTIME)
    @interface FieldInfo {
        int value() default 666;
    }
     
    @Target(ElementType.METHOD)
    @Retention(RetentionPolicy.RUNTIME)
    @interface MethodInfo {
        String name();
    }
     
    @ClassInfo("MyAnnotationTest")
    class MyAnnotation {
     
        @FieldInfo
        int anno;
     
        @FieldInfo(888)
        int tation;
     
        @MethodInfo(name = "myPrint")
        public void print() {
        }
     
     
        public static void main(String[] args) throws NoSuchMethodException {
            Class<?> clazz = MyAnnotation.class;
     
            ClassInfo classInfo = clazz.getAnnotation(ClassInfo.class);
            System.out.println(classInfo.value());
     
            Field[] fields = clazz.getDeclaredFields();
            FieldInfo fieldInfo = null;
            for (Field field : fields) {
                fieldInfo = field.getAnnotation(FieldInfo.class);
                System.out.println(fieldInfo.value());
            }
     
            Method method = clazz.getMethod("print");
            MethodInfo methodInfo = method.getAnnotation(MethodInfo.class);
            System.out.println(methodInfo.name());
        }
    }
     

反射 Reflection

  • Java 是静态语言,但具有一定的动态性。反射就是一个体现,它可以让我们在运行时分析一个类。JVM 加载一个类后会为该类生成一个 Class<T>类的对象,这个 Class 对象就封装了类的各个部分信息,我们可以通过 Class 对象来在运行时对类进行分析,执行其相应方法。

  • 获取 Class 对象的三种方式:

    • 对象名.getClass(),一般不用;
    • 类名.class 必须导包,依赖太强,不用;
      • 不会初始化 Class 对象;
    • Class.forName(全类名) 最常用;
      • 会初始化 Class 对象;
  • 使用反射

    • 先定义一个类
    public class MyReflection {
        public int publicField;
        private String privateField;
     
        public MyReflection() {
            System.out.println("公有无参构造函数执行了");
        }
     
        private MyReflection(int publicField, String privateField) {
            this.publicField = publicField;
            this.privateField = privateField;
            System.out.println("私有带参构造函数执行了");
     
        }
     
        // get、set方法...省略
     
        public void showPublic(){
            System.out.println("public方法被调用了");
        }
     
        private void showPrivate(){
            System.out.println("private方法被调用了");
        }
     
        public static void showStatic(s){
            System.out.println(s);
        }
    }
    • 获取并执行构造方法:
    public static void testConstructor() throws Exception {
        // 获取 Class对象
        Class clazz = Class.forName("com.reflection.MyReflection");
        
        // 获取所有公有构造方法
        Constructor[] constructors = clazz.getConstructors();
        for (Constructor c : constructors) {
            System.out.println(c);
        }
    	System.out.println();
        
        // 获取所有构造方法,包括私有等
        constructors = clazz.getDeclaredConstructors();
        for (Constructor c : constructors) {
            System.out.println(c);
        }
    	System.out.println(c);
        
        // 获取指定构造方法,参数为要获取的构造方法的参数的class对象;
        Constructor constructor = clazz.getDeclaredConstructor(int.class,String.class);
        // 暴力反射,忽略访问修饰符
        constructor.setAccessible(true);
        // 执行构造方法
        MyReflection o = (MyReflection) constructor.newInstance(1, "1");
        // 打印验证
        System.out.println(o.getPrivateField() + o.getPublicField());
    }
    // ----------执行结果--------
    public com.reflection.MyReflection()
        
    public com.reflection.MyReflection()
    private com.reflection.MyReflection(int,java.lang.String)
     
    私有带参构造函数执行了
    11
     
    • 获取成员变量:
    public static void testField() throws Exception {
        Class clazz = Class.forName("com.reflection.MyReflection");
     
        System.out.println("-----获取所有公有属性-----");
        Field[] fields = clazz.getFields();
        for (Field field : fields) {
            System.out.println(field);
        }
     
        System.out.println("-----获取所有属性-----");
        fields = clazz.getDeclaredFields();
        for (Field field : fields) {
            System.out.println(field);
        }
     
        System.out.println("-----获取指定属性,并调用-----");
        Field privateField = clazz.getDeclaredField("privateField");
        privateField.setAccessible(true);
        MyReflection o = (MyReflection) clazz.getConstructor(null).newInstance();
        privateField.set(o,"反射修改了私有属性");
        System.out.println(o.getPrivateField());
    }
     
    // ---------结果------------
    -----获取所有公有属性-----
    public int com.reflection.MyReflection.publicField
    -----获取所有属性-----
    public int com.reflection.MyReflection.publicField
    private java.lang.String com.reflection.MyReflection.privateField
    -----获取指定属性,并调用-----
    公有无参构造函数执行了
    反射修改了私有属性
    • 获取方法并调用:
    public static void testMethod() throws Exception {
        Class clazz = Class.forName("com.reflection.MyReflection");
     
        System.out.println("-----获取所有公有方法-----");
        Method[] methods = clazz.getMethods();
        for (Method m : methods) {
            System.out.println(m);
        }
     
        System.out.println("-----获取所有方法-----");
        methods = clazz.getDeclaredMethods();
        for (Method m : methods) {
            System.out.println(m);
        }
     
        System.out.println("-----获取指定方法,并调用-----");
        Method method = clazz.getMethod("showStatic",String.class);
        // 参数:执行对象 与 传参
        // 因为是静态方法,所以传递 null
        method.invoke(null, "静态方法执行了");
        
        method = clazz.getDeclaredMethod("showPrivate");
        MyReflection o = (MyReflection) clazz.getConstructor(null).newInstance();
        method.invoke(o);
    }
     
    //-----结果-----
    -----获取所有公有方法-----
    
    -----获取所有方法-----
    
    -----获取指定方法,并调用-----
    静态方法执行了
    公有无参构造函数执行了
    private方法被调用了