【Java 基础】注解

本文涉及的产品
全局流量管理 GTM,标准版 1个月
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
云解析 DNS,旗舰版 1个月
简介: 【Java 基础】注解

什么是注解?


  • 注解(Annotation)也称为元数据,是一种代码级别的说明


  • 注解是JDK1.5版本引入的一个特性,和类、接口是在同一个层次


  • 注解可以声明在包、类、构造器、字段、方法、成员变量、局部变量、方法参数等的前面,用来对这些元素进行说明


注解:就是具有特殊含义的标记(注解是给机器阅读的)


概述


作用:对Java中类、方法、成员变量做标记,然后进行特殊处理,至于到底做何种处理由业务需求来决定。


注解就是在代码里添加一些特殊标志,这些标志可以在编译,类加载,运行时被读取,并执行相应的处理,以便于其他工具补充信息或者进行操作。


注解与注释不同,会影响程序的执行,而注释不会。


注解的作用


  1. 编译检查


  • @Override:用来修饰方法声明。


  • 用来告诉编译器该方法是重写父类中的方法,如果父类不存在该方法,则编译失败。



  1. 代码分析


  • 通过代码里标识的注解对代码进行分析


  • 框架的配置( 框架 = 代码 + 配置 )


  • 具体使用请关注框架课程的内容的学习(注解去配置数据)


  1. 生成帮助文档


  • @author:用来标识作者姓名


  • @version:用于标识对象的版本号,适用范围:文件、类、方法


  • 使用@author和@version注解就是告诉Javadoc工具在生成帮助文档时把作者姓名和版本号也标记在文档中



使用过的注解



  • 用来修饰方法声明,告诉编译器该方法是重写父类中的方法,如果父类不存在该方法,则编译失败



  • Junit测试注解



自定义注解


注解的定义格式


定义注解使用关键字:@interface


public @interface 注解名{
   //内容
}


注解本质上就是一个接口。所有注解都会继承一个接口:Annotation


public interface 自定义注解名 extends java.lang.annotation.Annotation {}


带有属性的注解


  1. 属性的格式


  • 格式1:数据类型 属性名(); //无默认值的属性


  • 格式2:数据类型 属性名() default 默认值; //有默认值的属性


  1. 属性定义示例


public @interface Student {
  String name();                // 姓名
  int age() default 18;         // 年龄
  String gender() default "男"; // 性别
} 
// 该注解就有了三个属性:name,age,gender


  1. 属性适用的数据类型【记住】


  • 八种基本数据类型(int,short,long,double,byte,char,boolean,float)
  • String,Class,注解类型,枚举类

  • 以上类型的一维数组形式


注解的使用


注解的使用格式


//无属性注解
@注解名   例:@Test
//有属性注解
@注解名(属性=值,属性=值)


注解可以在类上,成员变量上,构造方法上,方法上,参数上…


有默认值的属性,可以不用进行赋值。


案例:


public @interface Book {
    String name();
    double price() default 100.0;
    String[] author();
}


建立一个BookStore的类,在类中定义成员变量,构造方法,成员方法


@Book(name = "西游记", author = {"吴承恩", "张三"})
public class BookStore {
    @Book(name = "三国", price = 10, author = {"罗贯中"})
    private String book;
    @Book(name = "三国", price = 10, author = {"罗贯中"})
    public BookStore() {
    }
    @Book(name = "三国", price = 10, author = {"罗贯中"})
    public void test() {
    }
}


如果注解中只有一个属性要赋值,而且名字是value,可以将value给省略,可以直接给值。


元注解


元注解的作用:


默认情况下,注解可以用在任何地方,比如类,成员方法,构造方法,成员变量等地方

如果要限制自定义注解的使用位置怎么办?那就要学习一个新的知识点:元注解

结论:元注解是用来约束自定义注解的使用范围、生命周期。


常用元注解:


常用元注解:@Target、@Retention


@Target


  • 作用:指明此注解用在哪个位置,如果不写默认是任何地方都可以使用


  • @Target可选的参数值在枚举类ElemenetType中包括:


TYPE: 用在类,接口上


FIELD:用在成员变量上


METHOD: 用在方法上


PARAMETER:用在参数上


CONSTRUCTOR:用在构造方法上


LOCAL_VARIABLE:用在局部变量上


PACKAGE:包


ANNOTATION_TYPE:注解上


@Retention


  • 作用:定义该注解的生命周期(有效范围)。


  • @Retention可选的参数值在枚举类型RetentionPolicy中包括:


SOURCE:注解只存在于Java源代码中,编译生成的字节码文件中就不存在了


使用场景:针对一些检查性的操作,比如:@Override ,就使用SOURCE注解


CLASS:注解存在于Java源代码、编译以后的字节码文件中,运行的时候内存中没有(默认值 )


使用场景:在编译时进行一些预处理操作,比如:生成一些辅助代码,就用CLASS注解


RUNTIME:注解存在于Java源代码中、编译以后的字节码文件中、运行时内存中,程序可以通过反射获取该注解


使用场景:要在运行时去动态获取注解信息,那只能用 RUNTIME 注解



元注解的使用:


@Target({ElementType.METHOD,ElementType.TYPE}) //元注解
@interface Stu{
    String name();
}
//类
@Stu(name="jack")  //成功
public class AnnotationDemo02 {
    // 成员变量
    @Stu(name = "lily")  // 编译失败
    private String gender;
    // 成员方法
    @Stu(name="rose")  //成功
    public void  test(){
    }
    // 构造方法
    @Stu(name="lucy") // 编译失败
    public AnnotationDemo02(){}
}


注解解析


获取注解数据的原理:


想要对注解中的数据进行解析,需要借助:AnnotatedElement 接口


  • Field,Method,Constructor,Class 等类都是实现了 AnnotatedElement 接口


AnnotatedElement 是一个接口,定义了解析注解的方法:


1. boolean isAnnotationPresent(Class<Annotation> annotationClass)   
   判断当前对象是否使用了指定的注解,如果使用了则返回true,否则false
   public class BookStore{
       @Book(name="书名")
       public void buy() // Method对象 判断该对象上是否使用了@Book注解
       {                 // boolean flag = Method对象.isAnnotationPresent(Book.class)
       }
   } 
2. T getAnnotation(Class<T> annotationClass) 
   根据注解类型获得对应注解对象
   // 获取注解的具体值见下面的综合案例
   // 获取对象上的自定义注解
   // Book bookAnno = Method对象.getAnnotation(Book.class); 
   //      bookAnno.属性   //获取注解中属性的值


Class,Constructor,Method,Field都会实现AnnotatedElement 接口


  • 解析类型上的注解:借助字节码对象(Class对象)


  • 解析构造方法上的注解:借助构造器对象(Constructor对象)


  • 解析方法上的注解:借助方法对象(Method对象)


  • 解析字段上的注解:借助字段对象(Field对象)


注解解析的步骤:(注解是书写在:类、方法、变量上)


1、利用反射技术获取注解作用的对象:类、方法、变量、构造方法


2、判断对象上是否有自定义注解存在


3、有:获取对象上的自定义注解


4、使用获取到的自定义注解对象,拿到注解中的属性值


注意:注解解析必须保证自定义注解生命周期在RUNTIME(程序运行中)


案例:


需求如下:


  1. 定义注解Book,要求如下:


  • 包含属性:String value() 书名


  • 包含属性:double price() 价格,默认值为 100


  • 包含属性:String[] authors() 多位作者


  • 限制注解使用的位置:类和成员方法上 【Target】


  • 指定注解的有效范围:RUNTIME 【Retention】


  1. 定义BookStore类,在类和成员方法上使用Book注解


  1. 定义TestAnnotation测试类获取Book注解上的数据


import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target({ElementType.METHOD,ElementType.TYPE}) //使用范围:方法、类
@Retention(RetentionPolicy.RUNTIME) //保证注解在程序执行时有效(适用于注解解析)
public @interface Book {
    String value();
    double price() default 100;
    String[] authors();
}
//类
public class BookStore {
    @Book(value = "Java入门", authors = {"张老师", "毕老师"})
    public void buy() {
        System.out.println("购书.....");
    }
}
//对注解中的数据进行解析
public class TestBookStore {
    public static void main(String[] args) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
        //反射套路:1、Class  2、构造器   3、Method
        Class<BookStore> bookStoreClass = BookStore.class;
        //获取构造器
        Constructor<BookStore> con = bookStoreClass.getConstructor();
        BookStore bookStore = con.newInstance();//实例化对象
        //获取Method
        Method method = bookStoreClass.getMethod("buy");
        //解析注解的步骤
        if(method.isAnnotationPresent(Book.class)){
            //获取Method对象上的Book注解
            Book bookAnno = method.getAnnotation(Book.class);
            //获取注解上的数据
            String bookName = bookAnno.value();
            double bookPrice = bookAnno.price();
            String[] bookAuthors = bookAnno.authors();
            System.out.println("书名:"+bookName);
            System.out.println("价格:"+bookPrice);
            System.out.println("作者:"+ Arrays.toString(bookAuthors));
        }
    }
}


小结


注解解析的步骤:


  1. 利用反射技术获取相关的对象:类、构造器、方法、变量


  1. 使用方法getAnnotation,获取自定义注解对象


  1. 使用注解对象,分别获取注解中的属性值


注解 综合案例


案例分析


  1. 模拟Junit测试的注释@Test,首先需要编写自定义注解@MyTest,并添加元注解,保证自定义注解只能修饰方法,且在运行时可以获得。


  1. 然后编写目标类(测试类),然后给目标方法(测试方法)使用 @MyTest注解,编写三个方法,其中两个加上@MyTest注解。


  1. 最后编写调用类,使用main方法调用目标类,模拟Junit的运行,只要有@MyTest注释的方法都会运行


import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
//自定义注解
@Target(ElementType.METHOD)//仅能应用在方法上
@Retention(RetentionPolicy.RUNTIME)//生命周期 :运行时
public @interface MyTest {
    //无属性注解
}
public class TestAnnotationParse {
    //方法1
    @MyTest
    public void method1(){
        System.out.println("我是方法1");
    }
    @MyTest
    public void method3(){
        System.out.println("我是方法3");
    }
    public void method2(){
        System.out.println("我是方法2");
    }
}
public class Test {
    public static void main(String[] args) throws IllegalAccessException, InstantiationException, InvocationTargetException {
        //获取Class对象
        Class<TestAnnotationParse> testAnnotationParseClass = TestAnnotationParse.class;
        //获取Class对象中,所有的Method方法
        Method[] methods = testAnnotationParseClass.getMethods();
        //遍历数组
        for (int i = 0; i < methods.length; i++) {
            //获取每一个Method对象
            Method method = methods[i];
            //判断Method对象上,是否存在@MyTest
            if(method.isAnnotationPresent(MyTest.class)){
                method.invoke(testAnnotationParseClass.newInstance());
            }
        }
    }
}


小结


注解解析的步骤:


  1. 获取Class对象 //类名.class、对象名.class、Class.forName(“…”)


  1. 基于Class对象,来获取:构造器/成员方法/成员变量 //getConstructor() getMethod() getField()


  1. 基于构造器/成员方法/成员变量,判断是否存在自定义注解 // isAnnotationPresent(注解.class)


  1. 存在:获取自定义注解对象 // 注解 对象 = 构造器/方法/变量/类 .getAnnotation(注解.class)


  1. 基于自定注解对象,获取其属性值 // 注解对象.属性()


注解+反射 综合案例


@Biao(value = "类上的value", name = "类上的name")
public class TestBiao {
    private Integer id;
    private String name;
    void test(){
        System.out.println("test");
    }
    String eat(Integer id){
        return "eat..." + id + new Date().getTime();
    }
    @Biao(value = "方法上的value", name = "方法上的name")
    void say(){
        System.out.println("say");
    }
    public static void main(String[] args) throws Exception{
        Class<?> clazz = Class.forName("testjava.annotation.TestBiao");
        if (clazz.isAnnotationPresent(Biao.class)) {
            Biao annotation = clazz.getAnnotation(Biao.class);
            System.out.println(annotation.name());
            System.out.println(annotation.value());
        }
        Method[] methods = clazz.getDeclaredMethods();
        if(methods == null){
            return;
        }
        for (Method method : methods) {
            boolean annotationPresent = method.isAnnotationPresent(Biao.class);
            if(annotationPresent){
                Biao annotation = method.getAnnotation(Biao.class);
                System.out.println(annotation.name());
                System.out.println(annotation.value());
                System.out.println("执行方法");
                method.invoke(clazz.newInstance());
            }
        }
    }
}


打印如下:


/**


  • 类上的name

  • 类上的value

  • 方法上的name

  • 方法上的value

  • 执行方法

  • say

  • */

相关文章
|
14天前
|
XML Java 编译器
Java注解的底层源码剖析与技术认识
Java注解(Annotation)是Java 5引入的一种新特性,它提供了一种在代码中添加元数据(Metadata)的方式。注解本身并不是代码的一部分,它们不会直接影响代码的执行,但可以在编译、类加载和运行时被读取和处理。注解为开发者提供了一种以非侵入性的方式为代码提供额外信息的手段,这些信息可以用于生成文档、编译时检查、运行时处理等。
50 7
|
2月前
|
XML Java 编译器
Java学习十六—掌握注解:让编程更简单
Java 注解(Annotation)是一种特殊的语法结构,可以在代码中嵌入元数据。它们不直接影响代码的运行,但可以通过工具和框架提供额外的信息,帮助在编译、部署或运行时进行处理。
97 43
Java学习十六—掌握注解:让编程更简单
|
19天前
|
Java 编译器 数据库
Java 中的注解(Annotations):代码中的 “元数据” 魔法
Java注解是代码中的“元数据”标签,不直接参与业务逻辑,但在编译或运行时提供重要信息。本文介绍了注解的基础语法、内置注解的应用场景,以及如何自定义注解和结合AOP技术实现方法执行日志记录,展示了注解在提升代码质量、简化开发流程和增强程序功能方面的强大作用。
55 5
|
1月前
|
Java 开发者 Spring
[Java]自定义注解
本文介绍了Java中的四个元注解(@Target、@Retention、@Documented、@Inherited)及其使用方法,并详细讲解了自定义注解的定义和使用细节。文章还提到了Spring框架中的@AliasFor注解,通过示例帮助读者更好地理解和应用这些注解。文中强调了注解的生命周期、继承性和文档化特性,适合初学者和进阶开发者参考。
56 14
|
1月前
|
前端开发 Java
[Java]讲解@CallerSensitive注解
本文介绍了 `@CallerSensitive` 注解及其作用,通过 `Reflection.getCallerClass()` 方法返回调用方的 Class 对象。文章还详细解释了如何通过配置 VM Options 使自定义类被启动类加载器加载,以识别该注解。涉及的 VM Options 包括 `-Xbootclasspath`、`-Xbootclasspath/a` 和 `-Xbootclasspath/p`。最后,推荐了几篇关于 ClassLoader 的详细文章,供读者进一步学习。
36 12
|
1月前
|
Java 编译器
Java进阶之标准注解
Java进阶之标准注解
32 0
|
2月前
|
JSON Java 数据库
java 常用注解大全、注解笔记
关于Java常用注解的大全和笔记,涵盖了实体类、JSON处理、HTTP请求映射等多个方面的注解使用。
43 0
java 常用注解大全、注解笔记
|
3月前
|
Arthas Java 测试技术
Java字节码文件、组成,jclasslib插件、阿里arthas工具,Java注解
Java字节码文件、组成、详解、分析;常用工具,jclasslib插件、阿里arthas工具;如何定位线上问题;Java注解
Java字节码文件、组成,jclasslib插件、阿里arthas工具,Java注解
|
2月前
|
IDE Java 编译器
java的反射与注解
java的反射与注解
17 0
|
3月前
|
Java 编译器 程序员
Java注解,元注解,自定义注解的使用
本文讲解了Java中注解的概念和作用,包括基本注解的用法(@Override, @Deprecated, @SuppressWarnings, @SafeVarargs, @FunctionalInterface),Java提供的元注解(@Retention, @Target, @Documented, @Inherited),以及如何自定义注解并通过反射获取注解信息。
Java注解,元注解,自定义注解的使用
下一篇
DataWorks