Java注解从入门到入土

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档


前言

注解其实就是一种标记,本质上是一种接口


一、Java 预置的注解

  • @Deprecated
    这个注解是用来标记过时的元素。首先定义一个 Hero 类,为其中的一个方法加上此注解:
public class Hero {
    @Deprecated
    public void say(){
        System.out.println("什么都没说");
    }
    
    public void run(){
        System.out.println("正在跑");
    }
}

测试一下,会发现编译器中的代码如下:
在这里插入图片描述
但是运行结果依旧可以运行。不耽误使用。

  • @Override
    表示这个方法重写或需要重写。

二、定义一个注解(元注解)

1、定义一个注解

如何定义一个注解,只需要在接口关键字之前加上‘@’:

public @interface TextAnnoation {
    
}

使用注解时,只需要在测试类中加上 ‘@TextAnnoation’ 即可。
所谓元注解,就是可以注解到注解上的注解,或者说元注解是一种基本注解,但是它能够应用到其它的注解上面。通俗理解,元注解是一张特殊的标签,它的作用和目的就是给其它普通标签进行解释说明的。
元标签有 @Retention@Documented@Target@Inherited

2、元注解

@Retention

Retention 的英文是保留期的意思。当 @Retention 应用到一个注解上的时候,它解释说明了这个注解的存活时间。它的取值如下:

取值描述作用范围使用场景
RetentionPolicy.SOURCE表示注解只保留在源文件,当java文件编译成class文件,就会消失源文件只是做一些检查性的操作,比如 @Override 和 @SuppressWarnings
RetentionPolicy.CLASS注解被保留到class文件,但jvm加载class文件时候被遗弃,这是默认的生命周期class文件(默认)要在编译时进行一些预处理操作,比如生成一些辅助代码(如 ButterKnife)
RetentionPolicy.RUNTIME注解不仅被保存到class文件中,jvm加载class文件之后,仍然存在运行时也存在需要在运行时去动态获取注解信息

使用形式为(以 RUNTIME 为例):

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

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

}

此代码中,我们指定 TestAnnotation 可以在程序运行周期被获取到,因此它的生命周期非常长。

@Documented

顾名思义,这个元注解肯定是和文档有关。它的作用是将注解中的元素包含到 Javadoc 中去。

@Target

Target 是目标的意思,@Target 指定了注解运用的地方。它取值如下:

取值作用目标
@Target(ElementType.TYPE)接口、类、枚举、注解
@Target(ElementType.FIELD)字段、枚举的常量
@Target(ElementType.METHOD)方法
@Target(ElementType.PARAMETER)方法参数
@Target(ElementType.CONSTRUCTOR)构造函数
@Target(ElementType.LOCAL_VARIABLE)局部变量
@Target(ElementType.ANNOTATION_TYPE)注解
@Target(ElementType.PACKAGE)

举个栗子:

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

@Retention(RetentionPolicy.CLASS)
@Target(ElementType.TYPE)
public @interface TextAnnoation {

}

@Inherited

Inherited 是继承的意思,但是它并不是说注解本身可以继承,而是说如果一个超类被 @Inherited 注解过的注解进行注解的话,你们它的子类没有被注解应用的话,那么这个子类就继承了超类的注解。说白了就是子类可以继承父类中的该注解

三、注解的属性

注解既然本质上是接口,那么注解里面自然就是抽象方法,也被叫做属性。
定义一个注解:

import java.lang.annotation.*;

@Retention(RetentionPolicy.CLASS)
@Target(ElementType.TYPE)
@Inherited
public @interface TextAnnoation {
    int id() default -1;//默认值为-1
    String massage() default "hello";//默认值为“hello”
}

测试类中使用该注解:

@TextAnnoation(id = 2,massage = "hello0")//如果给默认值在这个地方就不需要赋值了
public class Hero {
    @Deprecated
    public void say(){
        System.out.println("什么都没说");
    }

    public void run(){
        System.out.println("正在跑");
    }
}

四、注解的提取

把注解比作为标签,前面的内容将怎么写注解,然后贴到什么地方去,而现在我们要做的工作就是检阅这些标签内容。形象的比喻就是你把这些注解标签在合适的时候撕下来,然后检阅上面的信息。
想要正确检阅注解,离不开反射

1、类上注解的提取

举个栗子:

@TextAnnoation
public class Hero {
    public static void main(String[] args) {
        //判断 Hero 类上是够有 TextAnnoation 注解
        Boolean isHas = Hero.class.isAnnotationPresent(TextAnnoation.class);
        if(isHas){
            //获取到 TextAnnoation 注解
            TextAnnoation ann = Hero.class.getAnnotation(TextAnnoation.class);
            System.out.println(ann.id());
            System.out.println(ann.massage());
        }
    }
}

运行结果为:
在这里插入图片描述
注解里这么写的,所以会输出注解里面定义的默认属性:

public @interface TextAnnoation {
    int id() default -1;//默认值为-1
    String massage() default "hello";//默认值为“hello”
}

2、属性上注解的提取

注解是这么写的:

import java.lang.annotation.*;

@Retention(RetentionPolicy.RUNTIME)
public @interface TextAnnoation {
    int id() default -1;//默认值为-1
    String massage() default "hello";//默认值为“hello”
}

测试类:

import java.lang.reflect.Field;

public class Hero {
    @TextAnnoation(value = "hello")
    int a;
    public static void main(String[] args) throws NoSuchFieldException {
        Field f = Hero.class.getDeclaredField("a");//获取到属性a
        f.setAccessible(true);
        TextAnnoation c = f.getAnnotation(TextAnnoation.class);
        System.out.println(c.value());
    }
}

运行结果:
在这里插入图片描述

3、方法上注解的提取

注解是这么写的:

import java.lang.annotation.*;

@Retention(RetentionPolicy.RUNTIME)
public @interface TextAnnoation {
}

测试类:

public class Hero {
    @TextAnnoation
    public void text1(){
        System.out.println("text1方法");
    }

    public static void main(String[] args) throws NoSuchMethodException {
        Method m = Hero.class.getDeclaredMethod("text1");
        m.setAccessible(true);
        Annotation[] anns = m.getAnnotations();
        for(int i = 0;i < anns.length;i++){
            System.out.println(anns[i].annotationType().getSimpleName());
        }
    }
}

运行结果:
在这里插入图片描述

五、注解案例(举个栗子)

首先让我们写个注解:

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

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

}

然后我们写一个计算器类,里面有三个方法,但是其中有一个方法在调用时会出现异常。

public class Calculater {
    @Check
    public void add(){
        System.out.println("add");
    }
    @Check
    public void sub(){
        int t = 2/0;
        System.out.println("sub");
    }
    @Check
    public void times(){
        System.out.println("times");
    }
}

然后编写一下测试类:

public class Text {
    public static void main(String[] args) {
        Calculater cal = new Calculater();
        Class c = cal.getClass();//获取到Calculater的字节码对象
        Method[] m = c.getMethods();//获取Calculater的所有方法
        int tmp = 0;// 记录出错的次数
        StringBuilder bu = new StringBuilder();//记录出错的信息
        for (Method method : m) {
            if(method.isAnnotationPresent(Check.class)){
                try{
                    method.invoke(cal,null);
                }catch(Exception e){
                    tmp++;
                    bu.append("出错的方法是:" + method.getName() + "\n错误是:" + e.getCause().getMessage());
                }
            }
        }
        System.out.println("出错了" + tmp + "次");
        System.out.println(bu.toString());
    }
}

运行结果为:
在这里插入图片描述
@Check 注解本身里面没有任何东西,但是通过测试类可以为添加了 @Check 的方法检查是否出错。


总结

Java注解作用分类:

  • 编写文档:通过代码里标识的元数据生成文档【生成文档 doc 文档】
  • 代码 分析:通过代码里标识的元数据对代码进行分析【使用反射】
  • 编译检查:通过代码里标识的元数据让编译器能够实现基本的编译检查【Override】
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值