JavaSE进阶675-685 注解

开始时间:2021-02-21

注解

注解在Java中有,在Python中也有类似的,可以参考一下装饰器部分的注解
自定义注解

package BUPT20210222;

public @interface MyAnnotation {

}

[修饰符列表] @interface 注解类型名

Override注解

属于标志性注解,给编译器做参考

package BUPT20210222;

public class AnnotationTest {
    //@Override就是自带的一种注解
    //起到的作用是监督重写的方法是否是父类的方法
    //如果不是就会报错,

    //属于标志性注解,给编译器做参考
    @Override
    public String toString() {
        return "AnnotationTest{}";
    }
}

Override源代码如下

   	@Target(ElementType.METHOD)
    @Retention(RetentionPolicy.SOURCE)
    public @interface Override {
    }

可以观察到这个注解的注解,说明了注解只能用在方法上
不能用在类上

元注解

注解的注解被称为元注解
常见的元注解就是Target和Retention
Target标明注解能标在哪些地方上
Retention标明注解最终保存在哪些地方(Java源文件或者其他什么地方)

Deprecated注解

Deprecated注解用于标明已经过时的用法
以以下代码为例,当加了这个注解后
在这里插入图片描述
调用方法就会多一个横线

package BUPT20210222;

public class AnnotationTest02 {
    public static void main(String[] args) {
        doSome();
        AnnotationTest02 annotationTest02 = new AnnotationTest02();
        annotationTest02.doOther();
    }

    @Deprecated
    private static void doSome() {
        System.out.println("do Sth");
    }
    @Deprecated
    public void doOther() {
        System.out.println("do Other!");
    }

}


如果是在其他类调用方法,那么在代码本身上也会增加横线
在这里插入图片描述

注解中定义属性

package BUPT20210222;

public @interface MyAnnotation {
    //这里的name()不是方法是属性
    //要求使用这个注解的时候一定要在括号里协商
    //(name="XXX")这种格式,否则就要报错
    //有多个注解,就用逗号隔开,加了default默认值的话,可以不写
    String name();

    String color();

    int age() default 21;
}

package BUPT20210222;

public class AnnotationTest03 {
    public static void main(String[] args) {
        @MyAnnotation(name = "这是一个name()要求的格式",color = "红色")
        AnnotationTest02 annotationTest02 = new AnnotationTest02();
        annotationTest02.doOther();
    }
}

特殊情况,属性名为 “value”

package BUPT20210222;

public @interface MyAnnotation2 {
    String value();
}

当属性名为Value时,不需要写 value=
在这里插入图片描述
但只能有这一个属性,不能再加其他属性了,加了就不行了。
但加了的属性提供了默认值,只用value属性时也可以用

在这里插入图片描述
在这里插入图片描述

Deprecated的源码分析

现在来回顾一下Deprecated的源码

@Retention(RetentionPolicy.RUNTIME)
@Target(value={CONSTRUCTOR, FIELD, LOCAL_VARIABLE, METHOD, PACKAGE, MODULE, PARAMETER, TYPE})
public @interface Deprecated {

首先看@Retention
里面没有加name=的格式,说明了定义的是value属性
进入源码看一看

public @interface Retention {
    /**
     * Returns the retention policy.
     * @return the retention policy
     */
    RetentionPolicy value();
}

采用了.RUNTIME的形式,说明使用的是一个枚举类型

SOURCE不会在编译中保留下来
Class会被记录在字节码文件中
RUNTIME可以被编译器记录下来并且放虚拟机,同时可以被反射
public enum RetentionPolicy {
    /**
     * Annotations are to be discarded by the compiler.
     */
    SOURCE,

    /**
     * Annotations are to be recorded in the class file by the compiler
     * but need not be retained by the VM at run time.  This is the default
     * behavior.
     */
    CLASS,

    /**
     * Annotations are to be recorded in the class file by the compiler and
     * retained by the VM at run time, so they may be read reflectively.
     *
     * @see java.lang.reflect.AnnotatedElement
     */
    RUNTIME

再看

@Target(value={CONSTRUCTOR, FIELD, LOCAL_VARIABLE, METHOD, PACKAGE, MODULE, PARAMETER, TYPE})

可以看出value是一个数组,并且每个数组元素都是枚举
为了方便,将源码中的注释删掉了

public @interface Target {
    ElementType[] value();
}
public enum ElementType {
    /** Class, interface (including annotation type), enum, or record
     * declaration */
    TYPE,    FIELD,    METHOD,    PARAMETER,    CONSTRUCTOR,    LOCAL_VARIABLE,    ANNOTATION_TYPE,    PACKAGE,    TYPE_PARAMETER,    TYPE_USE,    MODULE,
  
    @jdk.internal.PreviewFeature(feature=jdk.internal.PreviewFeature.Feature.RECORDS,
                                 essentialAPI=true)
    RECORD_COMPONENT;
}

反射注解

package BUPT20210222;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

//只允许注解标注类和方法
@Target({ElementType.METHOD, ElementType.TYPE})
//允许注解被反射
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnotation03 {
}

获取类上面的注解

首先写注解的时候就要允许被反射,用Runtime

package BUPT20210222;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

//允许注解被反射
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnotation03 {
    String value();

    String name() default "zhangsai";
}

package BUPT20210222;

//将注解写在类上
@MyAnnotation03("123")
public class AnnotationTest03 {
    public static void main(String[] args) throws Exception {
        //反射获取该类
        Class c = Class.forName("BUPT20210222.AnnotationTest03");
        if (c.isAnnotationPresent(MyAnnotation03.class)) {
            //要加一个强制转型
            MyAnnotation03 myAnnotation03 = (MyAnnotation03) c.getAnnotation(MyAnnotation03.class);
            //可以直接读取属性
            System.out.println(myAnnotation03.name());
        }
    }
}

获取方法上面的注解

首先要获取类,才能进一步获取方法

package BUPT20210222;


import java.lang.reflect.Method;

public class AnnotationTest03 {
    //将注解写在方法上
    @MyAnnotation03("abc")
    private static void doSome() {
    }

    public static void main(String[] args) throws Exception {
        //反射获取该类

        Class c = Class.forName("BUPT20210222.AnnotationTest03");
        //多一个步骤,先获取类,再获取方法
        Method method = c.getDeclaredMethod("doSome");

        if (method.isAnnotationPresent(MyAnnotation03.class)) {
            //要加一个强制转型
            MyAnnotation03 myAnnotation03 = (MyAnnotation03) method.getAnnotation(MyAnnotation03.class);
            //可以直接读取属性
            System.out.println(myAnnotation03.value());
        }
    }
}

注解在反射中的一个应用

假设,需要一个注解来标记类,被标注的类必须有一个int类型的id属性,如果没有就报异常
先定义该注解

package BUPT20210222;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

//该注解只能出现在类上面
@Target(ElementType.TYPE)
//该注解可以被反射机制读取到
@Retention(RetentionPolicy.RUNTIME)
@interface MustHasIdPropertyAnnotation {

}

然后定义用户类User

package BUPT20210222;

@MustHasIdPropertyAnnotation
//加了这个注解,就必须把下面的int id写上`在这里插入代码片`
public class User {
    int id;
    String name;
    String password;
}

定义异常类

package BUPT20210222;

public class HasNotIdPropertyException extends Exception {
    public HasNotIdPropertyException(String s) {
        super(s);
    }

    public HasNotIdPropertyException() {
    }
}

写一个测试类

package BUPT20210222;

import java.lang.reflect.Field;

public class Test {
    public static void main(String[] args) throws Exception {
        Class userClass = Class.forName("BUPT20210222.User");
        boolean isOk = false;//给一个默认标记
        //首先判断用户类上面是否有这个注解
        if (userClass.isAnnotationPresent(MustHasIdPropertyAnnotation.class)) {
            //读取类中的所有字段
            Field[] fields = userClass.getDeclaredFields();
            //如果字段中有int id,就把标记改为true
            for (Field field : fields) {
                if ("id".equals(field.getName()) && "int".equals(field.getType().getSimpleName())) {
                    isOk = true;
                    break;
                }
            }
            //判断是否合法
            if (!isOk) {
                throw new HasNotIdPropertyException("报异常");
            }
        }
    }
}

结束时间 2021-02-22

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值