Java自定义注解

Posted 搬砖大强

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Java自定义注解相关的知识,希望对你有一定的参考价值。

Java-Java自定义注解


文章目录


前言

Java 骚操作之一:自定义注解


1、简介

注解是一种能被添加到java源代码中的元数据,方法、类、参数和包都可以用注解来修饰。注解可以看作是一种特殊的标记,可以用在方法、类、参数和包上,程序在编译或者运行时可以检测到这些标记而进行一些特殊的处理。

2、元注解

元注解的作用就是负责注解其他注解。Java5.0定义了4个标准的meta-annotation类型,它们被用来提供对其它 annotation类型作说明。Java5.0定义的元注解:

@Target,
@Retention,
@Documented,
@Inherited

下面我们看一下每个元注解的作用和相应分参数的使用说明。

2.1、@Target

表明该注解可以应用的java元素类型:

Target类型描述
ElementType.TYPE应用于类、接口(包括注解类型)、枚举
ElementType.FIELD应用于属性(包括枚举中的常量)
ElementType.METHOD应用于方法
ElementType.PARAMETER应用于方法的形参
ElementType.CONSTRUCTOR应用于构造函数
ElementType.LOCAL_VARIABLE应用于局部变量
ElementType.ANNOTATION_TYPE应用于注解类型
ElementType.PACKAGE应用于包
ElementType.TYPE_PARAMETER应用于类型变量
ElementType.TYPE_USE应用于任何使用类型的语句中(例如声明语句、泛型和强制转换语句中的类型)

2.2、@Retention
表明该注解的生命周期

生命周期类型描述
RetentionPolicy.SOURCE编译时被丢弃,不包含在类文件中
RetentionPolicy.CLASSJVM加载时被丢弃,包含在类文件中,默认值
RetentionPolicy.RUNTIME由JVM 加载,包含在类文件中,在运行时可以被获取到

2.3、@Document
表明该注解标记的元素可以被Javadoc 或类似的工具文档化。

2.4、@Inherited
表明使用了@Inherited注解的注解,所标记的类的子类也会拥有这个注解。

3、自定义注解

修饰符: 访问修饰符必须为public,不写默认为pubic;
关键字: 关键字为@interface;
注解名称: 注解名称为自定义注解的名称,使用时还会用到;
注解内容: 注解中内容,对注解的描述。

3.1 自定义注解

@Documented
@Inherited
@Target( ElementType.FIELD, ElementType.METHOD ,ElementType.TYPE)  //可以在字段、枚举的常量、方法
@Retention(RetentionPolicy.RUNTIME)
public @interface Init 
     String value() default "";

3.2 数据模型使用注解

public class User 
    private String name;
    private String age;

    public String getName() 
        return name;
    

    @Init("louis")
    public User setName(String name) 
        this.name = name;
        return this;
    

    public String getAge() 
        return age;
    

    @Init("22")
    public User setAge(String age) 
        this.age = age;
        return this;
    


3.3 定义一个“注解解析器”

public class userFactory 

        public static User create() 
            User user = new User();


            // 获取User类中所有的方法(getDeclaredMethods也行)
            Method[] methods = User.class.getMethods();


            try
            
                for (Method method : methods)
                
                    // 如果一个注解指定注解类型是存在于此元素上此方法返回true,否则返回false
                    //参数 -- 对应于注解类型的Class对象
                    if (method.isAnnotationPresent(Init.class))
                    
                        //此方法返回该元素的注解在此元素的指定注释类型(如果存在),否则返回null
                        Init init = method.getAnnotation(Init.class);
                        // 如果Method代表了一个方法 那么调用它的invoke就相当于执行了它代表的这个方法,在这里就是给set方法赋值
                        method.invoke(user, init.value());
                    
                
            
            catch (Exception e)
            
                e.printStackTrace();
                return null;
            


            return user;



3.4 运行的代码

   public static void main(String[] args) 
        User user = userFactory.create();
        user.setAge("30");
        System.out.println(user.getName());
        System.out.println(user.getAge());
    

3.5 结果


更多demo 参考 https://github.com/wangzhiqiang1008/common-framework

Java 注解自定义注解 ( 注解解析 )



【Java 注解】自定义注解 ( 注解属性定义与赋值 ) 博客中讲解了 注解属性 ;

【Java 注解】自定义注解 ( 元注解 ) 博客中讲解了注解中的元注解如何描述注解 ;

本篇博客开始讲解注解在程序中如何进行 解析 和 使用 ;


注解中定义了 若干 注解属性 , 那么就需要在某个阶段 , 将 注解属性 的值拿出来 , 在某个场合让其发挥出作用 ;

解析注解 : 获取 注解属性 的值 ;





一、定义注解



定义一个注解 :

package annotation;

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

/**
 * 描述 类名, 以及类名下的方法名
 * 该注解作用于类上
 * 注解保留到运行时
 */
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface Property {
    /**
     * 注解属性 : 需要反射的类名
     * @return
     */
    String name();

    /**
     * 注解属性 : 需要反射的方法名
     * @return
     */
    int age();
}





二、使用注解



使用上述 Property 注解 :

@Property(name = "Tom", age = 18)
public class Main {
    public static void main(String[] args) {
    }
}




三、解析注解



在 main 函数中解析 Main 类上的 @Property(name = "Tom", age = 18) 注解 ;


首先 , 获取该 Main 类的字节码对象 ; 在哪个类上添加了注解 , 就获取哪个类的字节码文件 ;

// 1. 获取该 Main 类的字节码对象,
//    哪个类上添加了注解 , 就获取哪个类的字节码文件
Class<Main> clazz = Main.class;

然后 , 获取字节码上的注解对象 , 通过调用 getAnnotation 获取指定注解类型的对象 , 也可以调用 getAnnotations 方法 , 获取作用在该字节码类上的所有注解 ;

// 2. 获取字节码上的注解对象
Property propertyAnnotation = clazz.getAnnotation(Property.class);

最后 , 从注解对象中 , 获取注解属性 , 调用 注解属性 对应的抽象方法即可获取 注解属性 值 ;

// 3. 调用 注解对象 中的抽象方法, 获取其返回值
//    注解的本质就是接口, 其中的注解属性本质是 抽象方法
//    注解对象可以直接调用注解超抽象方法,
//      是因为在内存中生成了该 注解 接口的子类对象, 实现了 name 和 age 方法
// 获取注解属性 name
String name = propertyAnnotation.name();
// 获取注解属性 age
int age = propertyAnnotation.age();

System.out.println("注解属性值 : name = " + name + " , age = " + age);

完整代码如下 :

package annotation;

@Property(name = "Tom", age = 18)
public class Main {

    public static void main(String[] args) {

        // 解析注解

        // 1. 获取该 Main 类的字节码对象,
        //    哪个类上添加了注解 , 就获取哪个类的字节码文件
        Class<Main> clazz = Main.class;

        // 2. 获取字节码上的注解对象
        Property propertyAnnotation = clazz.getAnnotation(Property.class);

        // 3. 调用 注解对象 中的抽象方法, 获取其返回值
        //    注解的本质就是接口, 其中的注解属性本质是 抽象方法
        //    注解对象可以直接调用注解超抽象方法,
        //      是因为在内存中生成了该 注解 接口的子类对象, 实现了 name 和 age 方法
        // 获取注解属性 name
        String name = propertyAnnotation.name();
        // 获取注解属性 age
        int age = propertyAnnotation.age();

        System.out.println("注解属性值 : name = " + name + " , age = " + age);
    }
}




四、通过注解对象获取注解属性的原理



通过注解对象获取注解属性的原理 :

注解的本质就是接口, 其中的注解属性本质是 抽象方法 , 注解对象可以直接调用注解超抽象方法 , 是因为在内存中生成了该 注解 接口的子类对象, 实现了 name 和 age 方法 , 返回值就是本类注解中的 注解属性值 ;

在 Main 类上标注了 @Property(name = "Tom", age = 18) 注解 , 该 Main 类运行时 , 则在内存中生成的 注解 接口的子类对象 , 大概形式如下 :

public class PropertyImpl implements Property {
    @Override
    public String name() {
        return "Tom";
    }

    @Override
    public int age() {
        return 18;
    }
}

因此 , 通过注解属性 , 调用 name 和 age 方法 , 可以获取到注解的 注解属性 值 ;

以上是关于Java自定义注解的主要内容,如果未能解决你的问题,请参考以下文章

java 自定义的注解有啥作用

Java自定义注解的使用

Java自定义注解

java自定义注解

Java 注解自定义注解 ( 使用注解实现简单测试框架 )

java自定义注解