Java 注解详细用法

注解的定义

注解通过 @interface 关键字进行定义。

public @interface MyAnnotation {
}

注解的应用

上面创建了一个注解,那么注解的的使用方法是什么呢。

@MyAnnotation 
public class MyTest {
	...
}

元注解

元注解是可以注解到注解上的注解,或者说元注解是一种基本注解,但是它能够应用到其它的注解上面。

  • @Retention:
    取值:

    • RetentionPolicy.SOURCE 注解只在源码阶段保留,在编译器进行编译时它将被丢弃忽视。
    • RetentionPolicy.CLASS 注解只被保留到编译进行的时候,它并不会被加载到 JVM 中。
    • RetentionPolicy.RUNTIME 注解可以保留到程序运行的时候,它会被加载进入到 JVM 中,所以在程序运行时可以获取到它们。
      例子:
    @Retention(RetentionPolicy.RUNTIME)
     public @interface MyAnnotation {
     }
    
  • @Documented: 能够将注解中的元素包含到 Javadoc 中去

  • @Target: 指定了注解运用的地方。
    @Target 有下面的取值

    • ElementType.ANNOTATION_TYPE 可以给一个注解进行注解
    • ElementType.CONSTRUCTOR 可以给构造方法进行注解
    • ElementType.FIELD 可以给属性进行注解
    • ElementType.LOCAL_VARIABLE 可以给局部变量进行注解
    • ElementType.METHOD 可以给方法进行注解
    • ElementType.PACKAGE 可以给一个包进行注解
    • ElementType.PARAMETER 可以给一个方法内的参数进行注解
    • ElementType.TYPE 可以给一个类型进行注解,比如类、接口、枚举
  • @Inherited: 如果一个超类被 @Inherited 注解过的注解进行注解的话,那么如果它的子类没有被任何注解应用的话,那么这个子类就继承了超类的注解
    例:

    @Inherited
    @Retention(RetentionPolicy.RUNTIME)
    public @interface MyAnnotation {
    }
    @MyAnnotation 
    public class ClassA {
    
    }
    
    public class  ClassB extends ClassA  {
    
    }
    

    注解 MyAnnotation 被 @Inherited 修饰,之后类 ClassA 被 MyAnnotation 注解,类 ClassB 继承 ClassA ,类 ClassB 也拥有 MyAnnotation 这个注解。

  • @Repeatable: 注解可多次应用,可重复

注解的属性

  • 注解的属性也叫做成员变量。
  • 注解只有成员变量,没有方法。
  • 注解的成员变量在注解的定义中以“无形参的方法”形式来声明,其方法名定义了该成员变量的名字,其返回值定义了该成员变量的类型;
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnotation {
    int id();
    String msg();
}

使用的时候可对其赋值:

@TestAnnotation(id=1,msg="hello annotation")
public class Test {

}

注 : 在 注 解 中 定 义 属 性 时 它 的 类 型 必 须 是 8 种 基 本 数 据 类 型 外 加 类 、 接 口 、 注 解 及 它 们 的 数 组 \color{red}{注: 在注解中定义属性时它的类型必须是 8 种基本数据类型外加 类、接口、注解及它们的数组} :8
可以给属性设置默认值,默认值用 default 关键值指定。
例:

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnotation {
    public int id() default -1;
    public String msg() default "Hello";
}
//有了默认值,可以这样使用
@MyAnnotation ()
public class Test {}
//所以无需要再在 @MyAnnotation 后面的括号里面进行赋值了

如 果 一 个 注 解 内 仅 仅 只 有 一 个 名 字 为 v a l u e 的 属 性 时 , 应 用 这 个 注 解 时 可 以 直 接 接 属 性 值 填 写 到 括 号 内 \color{red}{如果一个注解内仅仅只有一个名字为 value 的属性时,应用这个注解时可以直接接属性值填写到括号内} value
如:

public @interface MyAnnotation {
    public String value();
}
//可这样使用
@MyAnnotation ("hi")
int a;
//和
@MyAnnotation(value="hi")
int a;
的效果是一样的

注解没有任何属性

public @interface Perform {}
//使用时括号可以省略
@Perform
public void testMethod(){}

Java 预置的注解

  • @Deprecated 用来标记过时的元素
  • @Override 子类要重载父类的方法
  • @SuppressWarnings 阻止警告
  • @SafeVarargs 参数安全类型注解, 提醒开发者不要用参数做一些不安全的操作,它的存在会阻止编译器产生 unchecked 这样的警告
  • @FunctionalInterface 函数式接口注解
    函 数 式 接 口 ( F u n c t i o n a l I n t e r f a c e ) 就 是 一 个 具 有 一 个 方 法 的 普 通 接 口 , 函 数 式 接 口 可 以 很 容 易 转 换 为 L a m b d a 表 达 式 \color{red}{函数式接口 (Functional Interface) 就是一个具有一个方法的普通接口, 函数式接口可以很容易转换为 Lambda 表达式} (FunctionalInterface),Lambda

注解与反射

获取Class上注解的方法:

  • isAnnotationPresent() : 判断类的对象是否应用了某个注解
      public boolean isAnnotationPresent(Class<? extends Annotation> annotationClass) {}
    
  • getAnnotation() :方法来获取 Annotation 对象
    public <A extends Annotation> A getAnnotation(Class<A> annotationClass) {}
    
  • getAnnotations() :返回注解到这个元素上的所有注解 Annotation 对象
    public Annotation[] getAnnotations() {}
    

例子

例子一:
 @MyAnnotation()
 public class Test {
     public static void main(String[] args) {
         boolean hasAnnotation = Test.class.isAnnotationPresent(TestAnnotation.class);
         if ( hasAnnotation ) {
             TestAnnotation testAnnotation = Test.class.getAnnotation(TestAnnotation.class);
             System.out.println("id:"+testAnnotation.id());
             System.out.println("msg:"+testAnnotation.msg());
         }
     }
 }

例子二,可检索出属性方法上的注解:

 @MyAnnotation(msg="hello")
 public class Test {
     @Check(value="hi")
     int a;
 
     @Perform
     public void testMethod(){}
 
     @SuppressWarnings("deprecation")
     public void test1(){
         Hero hero = new Hero();
         hero.say();
         hero.speak();
     }
 
     public static void main(String[] args) {
 
         boolean hasAnnotation = Test.class.isAnnotationPresent(TestAnnotation.class);
 
         if ( hasAnnotation ) {
             TestAnnotation testAnnotation = Test.class.getAnnotation(TestAnnotation.class);
             //获取类的注解
             System.out.println("id:"+testAnnotation.id());
             System.out.println("msg:"+testAnnotation.msg());
         }
 
         try {
         	//取得类的指定属性
             Field a = Test.class.getDeclaredField("a");
             a.setAccessible(true);
             //获取一个成员变量上的注解
             Check check = a.getAnnotation(Check.class);
 
             if ( check != null ) {
                 System.out.println("check value:"+check.value());
             }
 
             Method testMethod = Test.class.getDeclaredMethod("testMethod");
 
             if ( testMethod != null ) {
                 // 获取方法中的注解
                 Annotation[] ans = testMethod.getAnnotations();
                 for( int i = 0;i < ans.length;i++) {
                     System.out.println("method testMethod annotation:"+ans[i].annotationType().getSimpleName());
                 }
             }
         } catch (NoSuchFieldException e) {
             // TODO Auto-generated catch block
             e.printStackTrace();
             System.out.println(e.getMessage());
         } catch (SecurityException e) {
             // TODO Auto-generated catch block
             e.printStackTrace();
             System.out.println(e.getMessage());
         } catch (NoSuchMethodException e) {
             // TODO Auto-generated catch block
             e.printStackTrace();
             System.out.println(e.getMessage());
         }
 	    }
 	}

使用场景

一个测试代码BUG的例子
Jiecha.java

@Retention(RetentionPolicy.RUNTIME)
public @interface Jiecha {

}

被测试的类
NoBug.java

public class NoBug {

    @Jiecha
    public void suanShu(){
        System.out.println("1234567890");
    }
    @Jiecha
    public void jiafa(){
        System.out.println("1+1="+1+1);
    }
    @Jiecha
    public void jiefa(){
        System.out.println("1-1="+(1-1));
    }
    @Jiecha
    public void chengfa(){
        System.out.println("3 x 5="+ 3*5);
    }
    @Jiecha
    public void chufa(){
        System.out.println("6 / 0="+ 6 / 0);
    }

    public void ziwojieshao(){
        System.out.println("我写的程序没有 bug!");
    }

}

测试类
TestTool.java

public class TestTool {

    public static void main(String[] args) {
        // TODO Auto-generated method stub

        NoBug testobj = new NoBug();

        Class clazz = testobj.getClass();

        Method[] method = clazz.getDeclaredMethods();
        //用来记录测试产生的 log 信息
        StringBuilder log = new StringBuilder();
        // 记录异常的次数
        int errornum = 0;

        for ( Method m: method ) {
            // 只有被 @Jiecha 标注过的方法才进行测试
            if ( m.isAnnotationPresent( Jiecha.class )) {
                try {
                    m.setAccessible(true);
                    m.invoke(testobj, null);

                } catch (Exception e) {
                    // TODO Auto-generated catch block
                    //e.printStackTrace();
                    errornum++;
                    log.append(m.getName());
                    log.append(" ");
                    log.append("has error:");
                    log.append("\n\r  caused by ");
                    //记录测试过程中,发生的异常的名称
                    log.append(e.getCause().getClass().getSimpleName());
                    log.append("\n\r");
                    //记录测试过程中,发生的异常的具体信息
                    log.append(e.getCause().getMessage());
                    log.append("\n\r");
                } 
            }
        }
        log.append(clazz.getSimpleName());
        log.append(" has  ");
        log.append(errornum);
        log.append(" error.");

        // 生成测试报告
        System.out.println(log.toString());

    }
}

测试的结果:

1234567890
1+1=11
1-1=0
3 x 5=15
chufa has error:

  caused by ArithmeticException

/ by zero

NoBug has  1 error.
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
电子图书资源服务系统是一款基于 Java Swing 的 C-S 应用,旨在提供电子图书资源一站式服务,可从系统提供的图书资源中直接检索资源并进行下载。.zip优质项目,资源经过严格测试可直接运行成功且功能正常的情况才上传,可轻松copy复刻,拿到资料包后可轻松复现出一样的项目。 本人系统开发经验充足,有任何使用问题欢迎随时与我联系,我会及时为你解惑,提供帮助。 【资源内容】:包含完整源码+工程文件+说明(若有),项目具体内容可查看下方的资源详情。 【附带帮助】: 若还需要相关开发工具、学习资料等,我会提供帮助,提供资料,鼓励学习进步。 【本人专注计算机领域】: 有任何使用问题欢迎随时与我联系,我会及时解答,第一时间为你提供帮助,CSDN博客端可私信,为你解惑,欢迎交流。 【适合场景】: 相关项目设计中,皆可应用在项目开发、毕业设计、课程设计、期末/期中/大作业、工程实训、大创等学科竞赛比赛、初期项目立项、学习/练手等方面中 可借鉴此优质项目实现复刻,也可以基于此项目进行扩展来开发出更多功能 【无积分此资源可联系获取】 # 注意 1. 本资源仅用于开源学习和技术交流。不可商用等,一切后果由使用者承担。 2. 部分字体以及插图等来自网络,若是侵权请联系删除。积分/付费仅作为资源整理辛苦费用。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值