java基础--16(注解)

1.java注解

                              

    通过反编译可以知道所有的注解都继承自 java.lang.annotation.Annotation

         

       

   注解是在一定的程度上把元数据与源代码文件文件结合在一起,而不是保存在外部文档中这一大势下所催生的。

2.注解的功能

       

        

        

   

@Target:表示该注解可以用于什么地方,可能的ElementType参数有:
CONSTRUCTOR:构造器的声明
FIELD:域声明(包括enum实例)
LOCAL_VARIABLE:局部变量声明
METHOD:方法声明
PACKAGE:包声明
PARAMETER:参数声明
TYPE:类、接口(包括注解类型)或enum声明

@Retention:表示需要在什么级别保存该注解信息。可选的RetentionPolicy参数包括:
SOURCE:注解将被编译器丢弃,SOURCE级别表示代码级别可见,经过编译器编译生成字节码对象时,此注解就没了。
CLASS:注解在class文件中可用,但会被VM丢弃,CLASS表示字节码对象级别可见,但是字节码对象被虚拟机加载时,这个注解会被抛弃,这是默认的可见级别。
RUNTIME:VM将在运行期间保留注解,因此可以通过反射机制读取注解的信息,RUNTIME表示运行时也可见,当虚拟机加载字节码对象时,此注解仍然可见。因此可以通过反射获取注解信息,然后完成相应的注解解析工作,一般自定义的注解都是运行时可见。

@Document:将注解包含在Javadoc中

@Inherited:允许子类继承父类中的注解

    @Target的的使用范围:

             

     @Retention:

        

        

    

   注解是jdk1.5后加入的新特性,可以理解为是一种标识,可以用在类、方法、属性...等上面,然后我们可以对这样有特殊标识的类做相应处理。java注解是附加在代码中的一些元信息,用于一些工具在编译、运行时进行解析和使用,起到说明、配置的功能。注解不会也不能影响代码的实际逻辑,仅仅起到辅助性的作用。包含在 java.lang.annotation 包中jdk1.5自带3种注解,也可以自定义注解,java自带三种注解。

@SuppressWarnings("unused")表示压制警告、忽略警告。

  比如下面就是警告,变量没有使用,

  

 添加忽略警告的注解:

  

 @Deprecated 用来标记某方法已过时。

可以看到过时的标志。

 

@Override 表示对方法覆盖。

2.实现自定义注解

    使用@interface关键字创建;java还提供了4种注解,专门负责新注解的创建。定义一个自定义注解,与定义一个接口类似,只不过在interface前加是哪个@。其内部可以添加属性值,其属性值的定义为 
      修饰符 返回值类型 属性名() [default value] 
      其中,修饰符只能用public 和abstract。 返回值为基本类型、字符串、枚举、注解以及以上类型的一维数组。 
定义自定义注解,还需要用到元注解,用于修饰自定义注解,一般我们会用到两个。@Retention和@Target。

              

      注解里面定义属性的方式和定义方法的方式差不多,访问修饰符必须是public或者默认的。

      

    

     

     对于跟反射息息相关的类:Field,Constructor,Method,都继承了AnnotatedElement接口,

    这个接口有这么多方法:判断指定类型的注解是否存在于此元素上,获取指定类型的注解(包括继承的),获得所有的注解(包括继承的)

         

 编写注解处理器

        

       

    注解的工作原理:

    

  

    注解本质是一个继承了Annotation 的特殊接口,其具体实现类是Java 运行时生成的动态代理类。而我们通过反射获取注解时,返回的是Java 运行时生成的动态代理对象$Proxy1。通过代理对象调用自定义注解(接口)的方法,会最终调用AnnotationInvocationHandler 的invoke 方法。该方法会从memberValues 这个Map 中索引出对应的值。而memberValues 的来源是Java 常量池。

  java编程思想上讲,如果没有用来读取注解的工具,那么注解也不会比注释更有用。

  自定义一个注解:

/**
 * 跟踪项目中的用例注解
 */
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface UserCase {
    public int id();
    public String description() default "no description";
}

 使用注解:

public class PassWordUtils {
    @UserCase(id = 1, description = "密码至少包含一个数字")
    public boolean validatePassword(String password) {
        return password.matches("\\w*\\d\\w*");
    }

    @UserCase(id = 2)
    public String encryptPassword(String password) {
        return new StringBuilder(password).reverse().toString();
    }

    @UserCase(id = 3, description = "新密码不能与旧密码相同")
    public boolean checkForNewPassword(List<String> prePasswords, String password) {
        return !prePasswords.contains(password);
    }

  注解解析器:

public class UserCaseTracker {

    public static void main(String[] args) {

        List<Integer> userCase = new ArrayList<Integer>();
        Collections.addAll(userCase, 1, 2, 3, 4, 5);
        trackUseCases(userCase, PassWordUtils.class);
    }

    private static void trackUseCases(List<Integer> userCase, Class<?> clazz) {
        //拿到类的所有方法
        for (Method method : clazz.getDeclaredMethods()) {
            //拿到方法上的注解
            UserCase aCase = method.getAnnotation(UserCase.class);
            //如果这个注解不为空,就打印他的id和描述信息
            if (aCase != null) {
                System.out.println("id:" + aCase.id() + ":::" + "description:" + aCase.description());
                userCase.remove(new Integer(aCase.id()));
            }
        }
    }
}

  我们看到了注解中注解元素的类型有int和String,那么究竟有哪些类型可以作为注解元素的类型呢?

 1.所有的基本类型

 2.Class

 3.注解

 4.枚举

 5.String

 6.以上类型的数组

 如果使用其他的类型编译器就会报错,不能使用包装类型,注解可以嵌套注解,这是一个非常有用的技巧。值得注意的是元素要么具有默认的值,要么在使用的时候提供值。非基本类型在定义默认的值时,不能用null,为了绕开这个约束我们只能自定义一些特殊的值来表示这个元素不存在,比如id为负数等等。

 首先第一步定义一个注解:第一个是他的作用范围,第二个是他的生命周期,表示运行时可见,因为要通过反射获取注解信息。

@Target({ElementType.METHOD,ElementType.FIELD,ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface FruitName {
    public String value() default "水果名字";
}

此时时定义的这个注解是一个空注解,没有任何意义,我要把它用起来给对象的属性赋值。

public class Apple {
    @FruitName("苹果")
    private String name;
}

然后就是要把这个对象的值给解析出来。

public class Test14 {
    public static void main(String[] args) {
        Test14 test14=new Test14();
        test14.getInfomation(Apple.class);
    }

    /**
     * 通过反射这个Class对象获取相关的注解,进行注解的解析
     * @param aClass
     */
    public void getInfomation(Class<?> aClass){
        //因为注解是在成员字段上,因此需要获得类的所有字段信息
        Field[] fields = aClass.getDeclaredFields();
        for (Field field : fields) {
            if (field.isAnnotationPresent(FruitName.class)){
                FruitName fruitName = field.getAnnotation(FruitName.class);
                System.out.println("水果名字:"+fruitName.value());
            }
        }
    }
}

  

 如何用过反射获得注解的信息?

T getAnnotation(Class) : 获得当前对象的指定的注解。 
Annotation[] getAnnotations() X: 获得当前对象的所有注解 
boolean isAnnotationPresent(annotationClass): 当前对象是否有这个注解。

3.注解的应用 java自定义注解解析及相关场景实现_Andyzhu_2005的博客-CSDN博客_自定义注解的场景及实现

     自定义注解+SpringMVC拦截器实现权限控制功能 

     自定义注解+SpringAOP实现日志记录功能

    

参考博客:java注解的自定义和使用 - 技术专家 - 博客园

                  java自定义注解解析及相关场景实现_Andyzhu_2005的博客-CSDN博客_自定义注解的场景及实现

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

时空恋旅人

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值