【java中的注解及使用示例】—— Annotation原理知多少?

x33g5p2x  于2022-02-24 转载在 Java  
字(5.1k)|赞(0)|评价(0)|浏览(418)

大家好,我是【1+1=王】, 热爱java的计算机(人工智能)渣硕研究生在读。
如果你也对java、人工智能等技术感兴趣,欢迎关注,抱团交流进大厂!!!
Good better best, never let it rest, until good is better, and better best.
往期精彩:

  • 【每天一个java设计模式(完)】 - 四万字实现23种设计模式(附示例源码)
  • 【攻克java集合系列(完结)】Java集合全面总结
  • 【CSDN 年终总结】结束与开始,一直在路上—— “1+1=王”的2021总结

概述

从JDK 5.0开始,Java增加了对元数据(MetaData)的支持,也就是Annotation(注解)。

在Java核心技术第2卷中对注解这样定义:
注解是那些插入到源代码中使用其他工具可以对其进行处理的标签。这些工具可以在源码层次上进行操作,或者可以处理编译器在其中放置了注解的类文件。
注解不会改变程序的编译方式。Java编译器对于包含注解和不包含注解的代码会生成相同的虚拟机指令。

注解其实就是代码里的特殊标记,这些标记可以被读取并执行相应的处理。

注解的一些可能的用法有:

  • 附属文件的自动生成,例如部署描述符或者bean信息类;
  • 测试、日志、事务语义等代码的自动生成。

注解是一种趋势,从某种角度来说:框架 = 注解 + 反射 + 设计模式

Annotation注解示例

1、生成文档相关的注解

  • @author
    标明开发该类模块的作者,多个作者之间用逗号分割
  • @date
    标明开发该类模块的时间
  • @version
    标明该类模块的版本
  • @see
    参考转向,也就是相关主题
  • @since
  • 从哪个版本开始增加的
  • @param
    对方法中参数的说明,如果没有参数就不能写(可以并列多个)
  • @return
    对方法返回值的说明,如果方法的返回值是void就不能写
  • @exception
    对方法可能抛出的异常的说明,如果方法没有用throws显示抛出异常就不能写(可以并列多个)
/**
 * @Description 这是注解的一个实例类
 * @author 1+1 =王
 * @date 2022/2/22 19:10
 * @since version 2.0
 */

public class AnnotationTest {

    /**
     * @Description 获取指定两个数之和
     * @param a
     * @param b
     * @return 两数之和
     */
    public int add(int a, int b){
        return a + b;
    }
}

2、在编译时进行格式检查

JDK中内置的三个基本注解

  • @Override
    限定重写父类方法,只能用于方法
  • @Deprecated
    用于表示所修饰的类或方法已过时
  • @SuppressWarnings
    用于抑制编译器的警告

3、跟踪代码依赖性,实现替代配置文件功能

<servlet>
    <servlet-name>LoginServlet</servlet-name>
    <servlet-class>com.java.code.Servlet<servlet-class>
</servlet>
<servlet-mapping>
    <servlet-name>LoginServlet</servlet-name>
    <url-pattern>/login</url-pattern>
<servlet-mapping>

用注解代替配置文件

package com.java.code.Servlet;

import com.java.code.Jdbc.StudentHomeworkJdbc;
import com.java.code.Model.User;

import javax.jws.WebService;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

@WebServlet("/login")
public class LoginServlet extends HttpServlet {

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        req.setCharacterEncoding("UTF-8");

        User user = new User();

        String username = req.getParameter("username");
        String password = req.getParameter("password");

        System.out.println(username+password);

        if(StudentHomeworkJdbc.selectByUsernameAndPassword(username,password) == 2){
            req.getRequestDispatcher("/jsp/login.jsp").forward(req,resp);
        }else {
            if(StudentHomeworkJdbc.selectByUsernameAndPassword(username,password) == 0){
                req.setAttribute("username",username);
                req.getRequestDispatcher("/jsp/usualUser.jsp").forward(req,resp);
            }else{
                req.getRequestDispatcher("/jsp/manager.jsp").forward(req,resp);
            }
        }
    }
}

自定义Annotation注解

创建一个注解类

注解声明为@interface(注:这与interface接口没有任何关系)

public @interface MyAnnotation {
    
}

内部定义成员通常用value表示

public @interface MyAnnotation {
    String value();
}

使用

@MyAnnotation(value = "Hello")
    public int add(int a, int b){
        return a + b;
    }

可以指定成员的默认值,使用default定义

public @interface MyAnnotation {
    String value() default "Hello";
}

如果自定义注解没有成员,表明是一个标识;如果注解有成员,在使用注解时必须指定成员的值。

  • 定义新的注解类型使用@interface
  • 自定义注解自动继承java.lang.annotation.Annotation接口
  • 注解的成员变量类型可以是8中基本数据类型、String类型、Class类型、Enum类型、Annotation类型或以上类型的数组。
  • 自定义注解必须配上注解的信息处理流程(使用反射)才有意义

JDK中的元注解

元注解用于修饰其他Annotation的定义,它是对现有的注解进行解释说明的注解。

4个元注解:@Retention、@Target、@Documented、@Inherited

  • @Retention:表示需要在什么级别保存该注释信息,用于描述注解的生命周期。

进入@Retention注解源码看到它只有一个RetentionPolicy类型的成员。


然后再进入RetentionPolicy中可以看到,他是一个枚举类型,包括三个值(SOURCE、CLASS、RUNTIME)。

三个值分别表示的意义如下:

  • RetentionPolicy.SOURCE:在源文件中有效,编译器直接丢弃这种策略的注释。

  • RetentionPolicy.CLASS:在class文件中有效,当运行java程序时,JVM不会保留注释。
    RetentionPolicy.RUNTIME:在运行时有效,当运行java程序时,JVM会保留注释。程序可以通过反射获取该注释。

  • @Target:用于描述注解的适用范围(即可以用在什么地方)

进入@Target注解源码看到它只有一个ElementType数组类型的成员。


ElementType也是一种枚举类型:

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
}
  • @Documented:说明该注解将被包含在javadoc中
  • @Inherited:说明子类可以继承父类中的该注解

通过反射获取注解信息

@MyAnnotation(value = "hello")
class User{
    private Integer id;
    private String name;
}

public class AnnotationTest {

    public static void main(String[] args) {
        Class clazz = User.class;
        Annotation[] annotations = clazz.getAnnotations();
        for(Annotation annotation:annotations){
            System.out.println(annotation);
        }
    }
}

JDK8中注解的新特性

可重复注解

如果我们需要定义重复注解,就必须给它定义容器类,还要使用 @Repeatable 注解修饰。

@Repeatable(MyAnnotations.class)
@Target({TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE})
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnotation {

    String value() default "hello";

}
/**
 * 容器类
 */
@Target({TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE})
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnotations {

    RepetitionAnnotation[] value();

}

测试重复定义注解

public class AnnotationTest {

    /**
     * @Description 获取指定两个数之和
     * @param a
     * @param b
     * @return 两数之和
     */
    @MyAnnotation(value = "Hello")
    @MyAnnotation(value = "你好")
    public int add(int a, int b){
        return a + b;
    }
}

类型注解

向 @Target 中添加两种类型 TYPE_PARAMETER和TYPE_USE。

相关文章