java注解--自定义注解--使用注解--元注解

注解概述

1.注解概述

        注解是JDK1.5的新特性。注解的使用,相当于为程序打上某种标记。

        注解(annotation),是一种代码级别的说明,和类 接口平级关系.

        javac编译器、开发工具和其他程序可以通过反射,来了解你的类及各种元素上有注解标记,根据不同的注解标记,完成对应的功能。

        注解可以加在包、类,属性、方法,方法的参数以及局部变量上定义

2.应用场景

        1.生产帮助文档 例如@author和@version 2.执行编译期的检查 例如:@Override

        3.框架的配置(替代配置文件)

3.常见注解

        1.@author:用来标识对象的作者名。

        2. @version:用于标识对象的版本号。

        3.@Override:描述方法的重写。

        4. @Deprecated:标记过时。

        5.@SuppressWarnings:压制警告。

         6.@FunctionalInterface:函数式接口

        7. @Test:测试注解

自定义注解

1.格式

        注解本质上就是一个接口,注解中的方法叫注解属性

2.注解属性定义

 

 

案例

// 无属性的注解
public @interface MyAnnotation1 {
}
// 带属性的注解: 属性类型 属性名();
public @interface MyAnnotation2 {
    // 1.基本类型
    byte a();
    short b();
    int c();
    long d();
    float e();
    double f();
    char g();
    boolean h();
​
    // 2.String类型
    String str();
​
    // 3.枚举类型
    Gender gender();
​
    // 4.注解类型
    MyAnnotation1 ma1();
    Override o();
​
    // 5.Class类型
    Class cls();
​
    // 6.以上类型的一维数组类型
    int[] arr1();
    String[] arr2();
    Gender[] arr3();
    MyAnnotation1[] arr4();
    Class[] arr5();
}

使用注解----重点

4.注解属性赋值

        如果一个注解没有属性,那么就不需要给注解属性赋值,直接使用即可 @注解名

        如果一个注解中有属性,那么使用注解的时候一定要给注解所有属性赋值 @注解名(属性名=值,属性名2=值2,...)

5.注意事项:

        一旦注解有属性了,使用注解的时候,属性必须有值

        若属性类型是一维数组的时候,当数组的值只有一个的时候可以省略{}

        如果注解中只有一个属性,并且属性名为value,那么使用注解给注解属性赋值的时候,注解属性          名value可以省略

        注解属性可以有默认值 格式:属性类型 属性名() default 默认值;

6.需求:演示自定义注解的定义及使用

// 没有属性的注解
public @interface MyAnnotation1 {
}
// 有属性的注解
public @interface MyAnnotation2 {
    // 属性
    String name();
    int age();
}
@MyAnnotation1
@MyAnnotation2(name = "itheima", age = 18)
public class Test {
    @MyAnnotation1
    @MyAnnotation2(name = "itheima", age = 18)
    int num;
​
    @MyAnnotation1
    @MyAnnotation2(name = "itheima", age = 18)
    public static void main(String[] args) {
        /*
            注解属性赋值
                如果一个注解没有属性,那么就不需要给注解属性赋值,直接使用即可      @注解名
                如果一个注解中有属性,那么使用注解的时候一定要给注解所有属性赋值   @注解名(属性名=值,属性名2=值2,...)
​
            注解可以使用在类\接口...上,成员变量上,成员方法上,形参上,构造方法上,局部变量上
         */
        @MyAnnotation1
        @MyAnnotation2(name = "itheima", age = 18)
        int a = 10;
    }
}

使用的注解的注意事项

public @interface MyAnnotation1 {
    String name();
    int age();
}
public @interface MyAnnotation2 {
    String[] arr();
}
public @interface MyAnnotation3 {
    String value();
}
public @interface MyAnnotation4 {
    String name() default "java";
    int age() default 18;
}
public @interface MyAnnotation23 {
    String[] value();
}
public @interface MyAnnotation44 {
    String name() default "java";
    int age() ;
}

public class Test {
    public static void main(String[] args) {
        /*
            注意事项:
                一旦注解有属性了,使用注解的时候,属性必须有值
                若属性类型是一维数组的时候,当数组的值只有一个的时候可以省略{}
                如果注解中只有一个属性,并且属性名为value,那么使用注解给注解属性赋值的时候,注解属性名value可以省略
                注解属性可以有默认值  格式:属性类型 属性名() default 默认值;
         */
    }
​
    //一旦注解有属性了,使用注解的时候,属性必须有值
    @MyAnnotation1(name="java",age = 20)
    public void method1(){}
​
    //若属性类型是一维数组的时候,当数组的值只有一个的时候可以省略{}
    //@MyAnnotation2(arr = {"itheima","itcast"})
    //@MyAnnotation2(arr = {"itheima"})
    //@MyAnnotation2(arr = "itheima")
    public void method2(){}
​
    // 如果注解中只有一个属性,并且属性名为value,那么使用注解给注解属性赋值的时候,注解属性名value可以省略
    //@MyAnnotation3(value = "java")
    @MyAnnotation3("java")
    public void method3(){}
​
​
    //若属性类型是一维数组的时候,当数组的值只有一个的时候可以省略{}
    //如果注解中只有一个属性,并且属性名为value,那么使用注解给注解属性赋值的时候,注解属性名value可以省略
    //@MyAnnotation23(value = {"java"})
    //@MyAnnotation23(value = "java")
    @MyAnnotation23("java")
    public void method23(){}
​
​
    //注解属性可以有默认值  格式:属性类型 属性名() default 默认值;
    @MyAnnotation4 // 所有属性都有默认值,使用的时候可以不给属性赋值,使用的就是默认值
    public void method4(){}
​
    @MyAnnotation44(age = 18) // 部分属性有默认值,那这部分属性可以不赋值,使用默认值,其余没有默认值的属性必须都赋值
    public void method44(){}
​
​
}

元注解

1.概述

        元注解是定义在注解上的注解,可以理解为由java定义好的,具有特殊意义的注解。

2.常见元注解

-@Retention:标记该注解保留到哪个操作阶段.

 

-@Target:标记该注解作用在什么位置

 

// 标记该注解可以使用在哪个位置
@Target(value = {ElementType.TYPE,ElementType.FIELD,ElementType.CONSTRUCTOR,ElementType.METHOD,ElementType.PARAMETER,ElementType.LOCAL_VARIABLE})
​
//@Target({ElementType.TYPE,ElementType.METHOD})
​
​
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnotation1 {
}
@MyAnnotation1
public class Test1 {
​
    @MyAnnotation1
    int num;
​
    @MyAnnotation1
    public Test1(int num) {
        this.num = num;
    }
​
    @MyAnnotation1
    public static void main(@MyAnnotation1 String[] args) {
        /*
            元注解: 定义注解的注解
            常见的元注解:
                @Target:标记该注解作用在什么位置,注解不加@Target元注解修饰,默认是任意位置都可以使用
                    @Target元注解中只有一个属性: ElementType[] value()
                    该属性的类型是ElementType数组类型,而ElementType是枚举类型
                    ElementType枚举类型的枚举值:
                        TYPE--------类型
                        FIELD-------成员变量
                        METHOD------成员方法
                        PARAMETER---参数
                        CONSTRUCTOR---构造方法
                        LOCAL_VARIABLE---局部变量
                        ...
                @Retention:标记该注解保留到哪个操作阶段.默认是源码阶段
                    @Retention元注解只有一个属性: RetentionPolicy value();
                    RetentionPolicy是枚举类型:
                        SOURCE---->源码阶段
                        CLASS----->字节码阶段
                        RUNTIME--->运行阶段
         */
        @MyAnnotation1
        int a = 10;
    }
}

注解解析

1.概述

-使用Java技术获得注解上数据的过程则称为注解解析。

-Annotation是描述字节码文件中注解的类,通过对Annotation对象类型判断,可以对”被注解元素”做相应操作。

2.解析原理

-1.java.lang.reflect.AnnotatedElement代表当前JVM中的“被注解元素”。

-2.Class、Method、Field、Constructor等实现了AnnotatedElement接口,都是可被注解的"元素"。

-3.(通过Java的反射机制)使用这个接口中声明的方法可以读取“被注解元素”的注解.

3.相关方法

T getAnnotation(Class<T>  annotationType):得到指定类型的注解对象。没有返回null。
​
boolean isAnnotationPresent(Class<?extends Annotation> annotationType):判断指定的 注解有没有。
​
​

案例

@Target({ElementType.TYPE,ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnotation {
    String name();
    int age();
}
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnotation1 {
}

@MyAnnotation(name = "java", age = 18)
@MyAnnotation1
public class Test {
    public static void main(String[] args) throws Exception{
        /*
            注解解析: 指的是获取注解或者获取注解属性值的过程
            被注解的元素: 被注解修饰的元素都是被注解元素,例如: Class,Method,Field,Constructor等等
            解析注解的步骤:
                1.获取被注解的元素
                2.通过被注解的元素获取其上面的注解
                3.通过注解获取注解上的属性值
            使用的API:  被注解元素接口AnnotatedElement的api---->所有被注解的元素都实现了该接口,也就意味着拥有这些方法
                <T extends Annotation> T getAnnotation(Class<T> annotationClass)
                          如果存在该元素的指定类型的注释,则返回这些注释,否则返回 null。
                 Annotation[] getAnnotations()
                          返回此元素上存在的所有注释。
                 Annotation[] getDeclaredAnnotations()
                          返回直接存在于此元素上的所有注释。
                 boolean isAnnotationPresent(Class<? extends Annotation> annotationClass)
                          如果指定类型的注释存在于此元素上,则返回 true,否则返回 false。
         */
        // 1.获取被注解的元素
        Class<Test> c = Test.class;
​
        // 2.通过被注解的元素获取其上面的注解
        MyAnnotation annotation = c.getAnnotation(MyAnnotation.class);
        MyAnnotation1 annotation1 = c.getAnnotation(MyAnnotation1.class);
​
        // 3.通过注解获取注解上的属性值
        System.out.println("annotation.name() = " + annotation.name());
        System.out.println("annotation.age() = " + annotation.age());
​
        // 4.获取所有的注解
        Annotation[] annotations = c.getAnnotations();
        for (Annotation an : annotations) {
            System.out.println("an = " + an);
        }
​
        // 5.判断Test类上是否有指定的注解
        boolean res1 = c.isAnnotationPresent(MyAnnotation.class);
        boolean res2 = c.isAnnotationPresent(MyAnnotation1.class);
        boolean res3 = c.isAnnotationPresent(Override.class);
        System.out.println("res1 = " + res1);// true
        System.out.println("res2 = " + res2);// true
        System.out.println("res3 = " + res3);// false
​
        System.out.println("--------------");
​
        // 1.获取被注解的元素---method方法
        Method m = c.getDeclaredMethod("method");
​
        // 2.获取该方法上的MyAnnotation的注解
        MyAnnotation annotation2 = m.getAnnotation(MyAnnotation.class);
​
        // 3.通过注解获取注解的属性值
        System.out.println(annotation2.name() + "," + annotation2.age());
​
        // 4.判断method方法上是否有MyAnnotation注解
        boolean res = m.isAnnotationPresent(MyAnnotation.class);
        boolean result = m.isAnnotationPresent(MyAnnotation1.class);
        System.out.println("res = " + res);// true
        System.out.println("result = " + result);//false
    }
​
    @MyAnnotation(name = "itheima", age = 1000)
    public static void method() {
        System.out.println("method");
    }
​
}

模拟Test注解

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface MyTest {
}
public class TestDemo {
​
    @MyTest
    public void test1(){
        System.out.println("test1...");
    }
​
    @MyTest
    public void test2(){
        System.out.println("test2...");
    }
​
    public void test3(){
        System.out.println("test3...");
    }
}
public class MyTestRun {
    public static void main(String[] args) throws Exception {
        // 模拟Test注解,点击方法名运行的解析代码
        /*// 1.获取TestDemo类的字节码对象
        Class<TestDemo> c = TestDemo.class;
        // 2.获取被注解的元素(test1方法)
        Method m = c.getMethod("test1");
        // 3.执行该方法
        TestDemo td = c.getDeclaredConstructor().newInstance();
        m.invoke(td);*/
​
        //System.out.println("----------------------");
​
        // 模拟Test注解,点击类名运行的解析代码
        // 1.获取TestDemo类的字节码对象
        Class<TestDemo> c = TestDemo.class;
​
        // 2.获取类中所有的成员方法
        Method[] methods = c.getMethods();
​
        // 3.循环遍历所有的方法
        for (Method m : methods) {
            // 4.判断该方法上是否有MyTest注解
            boolean res = m.isAnnotationPresent(MyTest.class);
            // 5.如果有,就执行该方法
            if (res){
                m.invoke(c.getDeclaredConstructor().newInstance());
            }
        }
​
​
    }
}

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值