Java注解

本文详细介绍了Java注解的使用,包括元注解如@Target、@Retention、@Documented、@Inherited和@Repeatable。讲解了Java自带的@SuppressWarning、@Deprecated、@Override等注解,以及如何自定义注解并使用。此外,还通过示例展示了注解在测试和参数传递中的应用,并探讨了注解的继承性和可重复性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Java修饰注解的注解(元注解)

  • @Target 设置目标范围
  • @Retention 设置保持性
  • @Documented 文档
  • @Inherited 注解继承
  • @Repeatable 此注解可以重复修饰

Java自带注解

  • @SuppressWarning 压制警告,修饰变量 / 方法 / 构造函数 / 类等
  • @SuppressWarning(“unchecked”) 忽略unchecked警告信息
  • @SuppressWarning(“deprecated”) 忽略过时方法的警告信息
  • @SuppressWarning({“unchecked”, “deprecated”}) 忽略unchecked和过时方法的警告信息(JDK自规定了这两种)
  • @Deprecated 描述某个方法或代码已过时,修饰类 / 类的元素 / 包
  • @Override 重写方法标记,修饰方法
  • @SafeVarargs 不会对不定项参数做危险操作
  • @FunctionInterface 声明功能性接口
public static void main(String[] args) {
        int a = 5;
        Date d = new Date();
    	// 警告
        System.out.println(d.getYear());
}
// Date类中的getYear()函数
@Deprecated
public int getYear() {
   return normalize().getYear() - 1900;
}

使用@SupperssWarning后

@SuppressWarnings("all")
public static void main(String[] args) {
    int a = 5;
    Date d = new Date();
    System.out.println(d.getYear());
}

无任何警告

Java自定义注解

  • 从JDK1.5引入,注解定义:扩展java.lang.annotation.Annotation注解接口
  • 注解可以包括的类型
  • 基本类型(int / short / long / float / double / byte / char / boolean)
  • String
  • Class
  • enum类型
  • 注解类型
  • 有前面类型组成的数组
注解使用的位置
  • @Target 可以限定位置
  • 允许的位置
  • 包 / 类 / 接口 / 方法 / 构造器 / 成员变量 / 局部变量 / 形参变量 / 类型参数
注解无参数
/**
 * @ClassName: Foo
 * @Author: Tang
 * @Date: 2021/6/4 15:01
 */
public class Foo {
    @Test
    public static void m1() {

    }

    @Test
    public static void m2() {
        throw new RuntimeException("m2 function error");
    }

    @Test
    public static void m3() {
    }

    @Test
    public static void m4() {
        throw new RuntimeException("m4 function error");
    }

    @Test
    public static void m5() {
    }
}
注解测试
public class Demo1 {
    public static void main(String[] args)throws Exception {
        // 记录通过以及不同的个数
        int pass = 0, failed = 0;
        String className = "exmple.com.demo8.Foo";
        // 获取Foo类中的所有方法
        for (Method m : Class.forName(className).getMethods()) {
            // 判断是否有@Test注解
            if (m.isAnnotationPresent(Test.class)) {
                try {
                    m.invoke(null);
                    pass++;
                } catch (Throwable ex) {
                    System.out.printf("测试: %s 失败: %s %n", m, ex.getCause());
                }
            }
        }
        System.out.printf("通过: %d, 失败 %d%n", pass, failed);
    }
}
// 表示该注解会保留在class文件中
@Retention(RetentionPolicy.RUNTIME)
// 表示该注解只会作用于方法上
@Target(ElementType.METHOD)
@interface  Test {

}
运行结果:

测试: public static void exmple.com.demo8.Foo.m4() 失败: java.lang.RuntimeException: m4 function error
测试: public static void exmple.com.demo8.Foo.m2() 失败: java.lang.RuntimeException: m2 function error
通过: 3, 失败 0

注解带参数
public class Foo {
    // 给a赋值
    @SingleTest(1)
    public static void m1(int a) {
        if (a < 0) {
            throw new RuntimeException("m1 function parameter error");
        }
    }
    // 等价于@SingleTest(-2)
    @SingleTest(value = -2)
    public static void m2(int b) {
        if (b < 0) {
            throw new RuntimeException("m2 function parameter error");
        }
    }
}
注解测试
public class Demo2 {
    public static void main(String[] args) throws ClassNotFoundException {
        int pass = 0, failed = 0;
        String className = "exmple.com.demo8.Foo";
        for (Method m : Class.forName(className).getMethods()) {
			// 判断是否有SingleTest注解
            if (m.isAnnotationPresent(SingleTest.class)) {
                // 输出函数名
                System.out.println(m.getName());
                // 获取方法上的注解
                SingleTest st = m.getAnnotation(SingleTest.class);

                try {
                    // 将获取到的值赋值给方法的形参
                    m.invoke(null, st.value()); // 等价SingleTest.value()
                    pass++;
                } catch (Throwable e) {
                    System.out.printf("测试: %s 失败: %s %n", m, e.getCause());
                    failed++;
                }

            }

        }
        System.out.printf("通过: %d, 失败: %d%n", pass, failed);
    }
}

// 表示该注解会保留在class文件中
@Retention(RetentionPolicy.RUNTIME)
// 表示该注解只能用于方法中
@Target(ElementType.METHOD)
@interface SingleTest {
    // 定义一个int类型变量,默认值为0
    // 与int a() default 0;等价
    int value() default 0;
}

注解带多个参数时

// 表示该注解会保留在class文件中
@Retention(RetentionPolicy.RUNTIME)
// 表示该注解只能用于方法中
@Target(ElementType.METHOD)
@interface SingleTest {
    // 定义一个int类型变量,默认值为0
    int a() default 0;
    int b() default 0;
}

// 使用注解时
@SingleTest(a = 1)
public static void m1(int a) {
    if (a < 0) {
      throw new RuntimeException("m1 function parameter error");
    }
}
@SingleTest(a = -2, b = 2)
public static void m2(int a, int b) {
  if (b < 0) {
     throw new RuntimeException("m2 function parameter error");
  }
}

// 反射机制给方法形参赋值时
m.invoke(null, st.a(), st.b()); // 等价于SingleTest.a()

Java元注解

  • @Target 设置目标范围
  • @Retention 设置保持性
  • @Inherited 注解继承
  • @Repeatable 此注解可以重复修饰
  • @Documented 文档
@Rentention注解
  • 用来修饰其他注解的存在范围
  • RetentionPolicy.SOURCE 注解仅存在源码,不在class文件中
  • RetentionPolicy.CLASS 默认的保留策略。注解存在于.class文件中,当但不能被JVM加载,即不能使用反射获取到
  • RetentionPolicy.RUNTIME 注解可以被JVM运行时访问到。通常情况下,可以结合反射来实现一些功能
@Target注解
  • 限定注解作用于什么位置
  • ElementType.ANNOTAION_TYPE (修饰注解)
  • ElementType.CONSTRUCTOR
  • ElementType.FIELD
  • ElementType.LOCAL_VARIABLE (局部变量)
  • ElementType.METHOD
  • ElementType.PACKAGE
  • ElementType.RARAMETER (参数)
  • ElementType.TYPE (任何类型,即上面的类型都可以修饰)
@Inherited注解
  • 让一个类和它的子类都包括某个注解
  • 普通注解没有继承功能
public class Demo3 {
    public static void main(String[] args) throws ClassNotFoundException {
        Class c1 = Class.forName("exmple.com.demo8.MySupperClass1");
        Class c2 = Class.forName("exmple.com.demo8.MySubClass1");
        System.out.println("使用了@Inherited: ");
        System.out.println("父类: " + c1.getAnnotations().length);
        System.out.println("子类:" + c2.getAnnotations().length);

        System.out.println("没有使用@Inherited: ");
        Class c3 = Class.forName("exmple.com.demo8.MySupperClass2");
        Class c4 = Class.forName("exmple.com.demo8.MySubClass2");
        System.out.println("父类:" + c3.getAnnotations().length);
        System.out.println("子类:" + c4.getAnnotations().length);
    }
}
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@interface MyAnnotation1 {}

@MyAnnotation1
class MySupperClass1 {}

class MySubClass1 extends MySupperClass1 {}

@Retention(RetentionPolicy.RUNTIME)
@interface MyAnnotation2 {}

@MyAnnotation2
class MySupperClass2 {}

class MySubClass2 extends MySupperClass2 {}
运行结果

使用了@Inherited:
父类: 1
子类:1
没有使用@Inherited:
父类:1
子类:0

可以看出使用@Inherited可以使子类包含父类的注解

@Repleatable注解
  • 自JDK1.8引入
  • 表示被修饰的注解可以重复应用标注
  • 需要定义注解和容易注解
public class Demo4 {
    public static void main(String[] args) throws ClassNotFoundException {
        String className = "exmple.com.demo8.Student";
        // 获取目标对象的所有方法
        for (Method m : Class.forName(className).getMethods()) {
			// 判断是否有容器注解
            if (m.isAnnotationPresent(RepeatableAnnotations.class)) {
                RepeatableAnnotation[] annos = 					             m.getAnnotationsByType(RepeatableAnnotation.class);

                for (RepeatableAnnotation anno : annos) {
                    System.out.println(anno.a() + "," + anno.b() + "," + anno.c());
                    try {
                        // 将获取到的值传递给方法形参
                        m.invoke(null, anno.a(), anno.b(), anno.c());
                    } catch (Throwable ex) {
                        System.out.printf("测试: %s 失败: %s %n", m, ex.getCause());
                    }

                }
            }

        }

    }
}
class Student {
    @RepeatableAnnotation(a = 1, b = 2, c = 3)
    @RepeatableAnnotation(a = 1, b = 2, c = 4)
    public static void add(int a, int b, int c) {
        if (c != a + b) {
            throw new RuntimeException("add function error");
        }
    }
}
@Retention(RetentionPolicy.RUNTIME)
// 运行该注解可以重复标注
@Repeatable(RepeatableAnnotations.class)
@interface RepeatableAnnotation {
    int a() default 0;
    int b() default 0;
    int c() default 0;
}
// 容器注解
@Retention(RetentionPolicy.RUNTIME)
@interface RepeatableAnnotations {
    RepeatableAnnotation[] value();
}
运行结果

1,2,3
1,2,4
测试: public static void exmple.com.demo8.Student.add(int,int,int) 失败: java.lang.RuntimeException: add function error

@Documented注解

指明这个注解可以被JavaDoc工具解析,形成帮助文档

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值