Java - 注解

1. 注解的概念

注解(Annotation)就是对声明的元素进行说明,注释的。

元素可以是:类、字段、方法、方法参数…

给元素添加注解相当于贴了一个标签,至于此注解什么时候用、怎么用不归它管。
单但给某个元素添加了个注解,却不写该注解相关的逻辑判断,屁用没有。

比如快递的分拣:

集散中心有很多快递,快递上有商家贴的标签,标签上有收件人的地址等信息。
分拣机器通过标签将同一个城市、同一个区的快递放到一个口袋中。

商家给货物贴标签的动作就相当于给某个元素添加注解。
分拣机通过标签分拣相当于程序通过注解区分元素(具体怎么用由你决定,区分只是其中一种逻辑而已)

2. 注解可以声明的位置

包上、类上、方法上、字段上、形参上、局部变量上等等。

package java.lang.annotation;

public enum ElementType {
    /** Class, interface (including annotation type), or enum declaration */
    //类、接口、注解类、枚举类型
    TYPE,

    /** Field declaration (includes enum constants) */
    //字段
    FIELD,

    /** Method declaration */
    //方法
    METHOD,

    /** Formal parameter declaration */
	//形参
    PARAMETER,

    /** Constructor declaration */
    //构造器上
    CONSTRUCTOR,

    /** Local variable declaration */
    //局部变量上
    LOCAL_VARIABLE,

    /** Annotation type declaration */
    //注解类上
    ANNOTATION_TYPE,

    /** Package declaration */
    //包上
    PACKAGE,

    /**
     * Type parameter declaration
     *
     * @since 1.8
     */
     //自定义类型参数上
    TYPE_PARAMETER,

    /**
     * Use of a type
     *
     * @since 1.8
     */
    //使用类型的任意语句中
    TYPE_USE
}

3. 元注解

元注解就是自定义注解上的注解,作用是设置自定义注解的作用域、声明位置等信息。

Java元注解:
@Retention	:描述自定义注解被保留的阶段
@Target		:描述自定义注解的作用位置
@Documented :描述自定义注解是否被抽取到API文档中
@Inherited	:描述自定义注解是否被子类继承
@Native		:表示这个字段可以被本地代码引用,常常被代码生成工具使用.
@Repeatable	:重复注解,允许一个元素上多次使用同一个注解

4. 自定义注解

package annotation_test;

import java.lang.annotation.*;

/**
 * @Date: 2022/4/28 11:04
 * @author: ZHX
 * @Description: 自定义注解
 */
@Retention(RetentionPolicy.SOURCE)
@Target(ElementType.ANNOTATION_TYPE)
public @interface CustomAnnotation {   //注解隐式继承Annotation接口,注解也是个接口

    //可定义属性的类型:基本类型、String、枚举、注解、以上类型的数组

    int i();

    String value() default ""; //如果属性只有value则可以不写。

    Override c();//注解类型

    ElementType e1();  //枚举类型

    ElementType[] e2();  //枚举数组,使用时数组只有一个值可以省略大括号.

}

5. JDK内置的注解

JDK预定义好的注解,直接用就好了。

@Override					检查覆盖重写
@Deprecated					标记已过时
@SupressWarinings("all")	压制警告
@FunctionalInterface		标识该接口符合函数式接口
@SafeVarargs				断言参数安全,压制"unchecked"警告

6. 练习:注解+反射批量执行方法

要求:

有个annotation_test包,包中有多个类,每个类中都有多个方法。

将包中所有类中的所有带有@Test注解的方法都执行一遍。

在这里插入图片描述

类结构、自定义注解结构

package annotation_test;

/**
 * @Date: 2022/4/28 14:28
 * @author: ZHX
 * @Description:
 */
public class A {

    @Test
    public void method1(){
        System.out.println("A:method1");
    }

    @Test
    public void method2(){
        System.out.println("A:method2");
        System.out.println("");
    }

    @Test
    public void method3(){
        System.out.println("A:method3");
    }
}

package annotation_test;

/**
 * @Date: 2022/4/28 14:28
 * @author: ZHX
 * @Description:
 */
public class B {

    @Test
    public void method1(){
        System.out.println("B:method1");
    }

    @Test
    public void method2(){
        System.out.println("B:method2");
        System.out.println("");
    }

    @Test
    public void method3(){
        System.out.println("B:method3");
    }
}

package annotation_test;

import java.lang.annotation.*;

/**
 * @Date: 2022/4/28 11:04
 * @author: ZHX
 * @Description: 自定义注解@Test, 用来批量测试方法
 */
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface Test {   //注解隐式继承Annotation接口,注解也是个接口
}

实现

import java.io.File;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.URL;

/**
 * @Date: 2022/4/28 14:30
 * @author: ZHX
 * @Description: 简单实现下包扫描,批量执行指定方法。Junit测试一样的原理,递归+反射+注解实现的。
 */
public class Test {

    public static void main(String[] args) throws ClassNotFoundException, IOException, InvocationTargetException, IllegalAccessException, InstantiationException {

        //包扫描,将annotation_test包中的所有类的所有带@Test方法
        String packageName = "annotation_test";
        ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader();

        //获取资源的url路径
        URL url = contextClassLoader.getResource(packageName);

        String path = url.getPath();// /D:/Project/java-advance/out/production/day15-annotation/annotation_test

        String protocol = url.getProtocol();

        //是文件,
        if (protocol.equals("file")) {

            File directory = new File(path);

            //得到包下的所有文件和文件夹。
            File[] files = directory.listFiles();

            for (File file : files) {

                String f = file.getPath(); //  D:\Project\java-advence\out\production\day15-annotation\annotation_test\B.class

                //是.class文件,符合类加载
                if (f.endsWith(".class")) {

                    //处理得到 类的全限定名 包名.类名
                    String prefix = Test.class.getClassLoader().getResource("").getPath().substring(1);
                    f = f.substring(prefix.length(), f.length() - 6).replace("\\", ".");

                    //利用反射 判断方法上是否有@Test注解并执行
                    Class<?> clazz = Class.forName(f);
                    //跳过接口
                    if (clazz.isInterface()) continue;

                    Method[] methods = clazz.getMethods();
                    Object o = clazz.newInstance();
                    for (Method method : methods) {
                        if (method.isAnnotationPresent(annotation_test.Test.class)) {
                            method.invoke(o);
                        }
                    }
                }
            }
        }
    }
}

注: junit测试底层就是这个原理,什么spring注解等等都是这样实现的。

7. 参考资料

B站黑马程序员

不懂注解?那就自己写一个,安排的明明白白

百度百科

java中@Repeatable的理解

java元注解@Native && @Repeatable (java8 新增)

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值