注解(注释)

注解

注解的概念,作用

  1. 什么是“注解”:JDK1.5提出“注解”。在我们编写代码的时候,使用@Override,@FactionalInterface,@Test(JUnit),这些注解都是写在“源码”中。作为一个“标记”,告诉“注解解析器”怎样编译、运行下面的代码。
    1. 告诉编译期中的“注解解析器”下面的代码应该怎样编译
    2. 使用“注解解析器”来加载有“注解”的代码,根据注解的使用,来决定怎样执行下面的代码
  2. 实现注解的两个元素:
    1. 注解本身–我们可以自定义注解,注解本质上是一个“接口”。但定义时有自己的关键字@interface
    2. 注解解析器–一个类。如果“注解”时给编译器用的,就需要将“注解解析器”随着编译器一起启动。否则这个“注解”就应该有一个单独的“注解解析器”来单独启动,加载使用了注解的类,来决定怎样去执行。

自定义注解的基本格式:

  1. 我们可以自定义注解:
	语法:public @interface 注解名{
		  }
  1. 示例代码:
public @interface MyTest {
}
//使用这个注解:
import org.junit.Test;
@MyTest
public class Student {
    @MyTest
    private String name;
    @Test
    @MyTest
    public void show(){
        System.out.println("show()...");
    }
}

  1. 这个注解有两个问题:
    1. 我们的注解可以放在一个类的任意位置—而@Test注解只能用在“方法”上
    2. 我们的注解没有任何作用—因为没有注解解析器。
      这两个问题全部由“元注解”解决!!!

元注解

  1. 元注解:它也是一个注解,是JDK中定义好的,元注解只用在“注解的定义上”,它可以约束新注解:

    1. 使用的位置
    2. 生命周期
  2. 使用位置:@Target元注解
    ElementType.METHOD是@Target注解的“属性”,如果像约束新注解只能用在:成员方法上。@Target(ElementType.METHOD) public @interface MyTest{ }
    它的可选有:

    1. ElementType.TYPE:类,接口
    2. ElementType.FIELD:成员变量
    3. ElementType.METHOD:成员方法
    4. ElementType.PARAMETER:方法参数
    5. ElementType.CONSRUCTOR:构造方法
    6. ElementType.LOCAL_VARIABLE:局部变量
  3. 生命周期:@Retention元注释
    例如:@Retention(RetentionPolicy,SOURCE),约束新注释只存在于“源码中”,不会被编译到class中
    RetentionPolicy.SOURCE是@Rentention元注释的“属性”,它的可选值:

    1. RetentionPolicy.SOURCE:注释只存在于“源码”中,例如:@Override
    2. RetentionPolicy.CLASS:注释可以存在于“源码”,“class”文件中
    3. RetentionPolicy.RUNTIME:注释可以存在于“源码”,“class文件”,运行时会被加载到内存。例如:@Test
代码演示:

自定义注解

@Target({ElementType.METHOD})//1.约束新注解:使用的位置
@Retention(RetentionPolicy.RUNTIME)//2.约束新注解:生命周期
public @interface MyTest {
}

代码图解

在这里插入图片描述

解析注解

  1. 这里我们单独编写一个“类”,包含main()方法,作为我们自定义的注解@MyTest注解的“注解解析器”,来模拟JUnit的@Test的注解解析器。
  2. 在这个“注解解析器”中,需要使用“反射”技术
  3. 步骤:
    1. 编写一个注解
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface MyTest {
}

2. 使用这个注解:
public class Student {
    @MyTest
    public void show1(){
        System.out.println("show1");
    }
    @MyTest
    public void show2(){
        System.out.println("show2");
    }
}

3. 注解解析器:
public class Demo09 {
    public static void main(String[] args) throws Exception {
        //1.获取Student的Class对象
        Class stuClass = Class.forName("com.itheima.demo09_注解解析器.Student");

        //2.创建它的对象
        Object o = stuClass.getConstructor().newInstance();

        //3.获取它内部所有的"公有"方法
        Method[] ms = stuClass.getMethods();

        //4.遍历这些方法
        for (Method m : ms) {
            //5.判断这个方法上是否使用了@MyTest注解
            if(m.isAnnotationPresent(MyTest.class)){
                //6.执行此方法
                m.invoke(o);
            }
        }
    }
}

定义包含属性的注释:

  1. 注释中可以定义属性:
    格式:
    public @interface MyTest{
    //属性格式:
    数据类型名 属性名() [default 值];
    }
  2. 注释中属性的作用:可以更详细的对注释进行设置。
  3. 其它说明:
    1. 属性的“数据类型”可以是以下几种类型:
      1. 所有的“基本数据类型”(四类八种)
      2. String类型
      3. Class类型
      4. 枚举类型
      5. 注解类型
      6. 以上类型的“数组”类型
        注意:没有“包装类”类型
    2. 如果“注释”中只有一个属性,而且属性名叫“value”
      public @interface MyTest{
      int value;
      }
      在使用时:可以简写也可以完整写
public class Student {
    @MyTest(1)//可以简化写为:@MyTest(1),也可以完整写:@MyTest(value = 1)
    public void show2(){
        System.out.println("show2() index = 1");
    }
    @MyTest(2)
    public void show1(){
        System.out.println("show1() index = 2");
    }

    public void test1(){
        System.out.println("test1()");
    }
    @MyTest(3)
    public void test2(){
        System.out.println("test2() index = 3");
    }


}

代码演示:

测试类:

package com.itheima.demo10_定义带属性的注解;

import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.Comparator;

public class Demo10 {
    public static void main(String[] args) throws Exception {
        //1.获取Class
        Class stuClass = Class.forName("com.itheima.demo10_定义带属性的注解.Student");
        //2.创建对象
        Object o = stuClass.getConstructor().newInstance();

        //3.获取所有"公有"成员方法
        Method[] ms = stuClass.getMethods();

        //4.对方法进行排序,根据@MyTest注解的index属性值排序
        Arrays.sort(ms, new Comparator<Method>() {
            @Override
            public int compare(Method o1, Method o2) {
                //1.判断两个方法上都使用的@MyTest注解
                if(o1.isAnnotationPresent(MyTest.class) &&
                        o2.isAnnotationPresent(MyTest.class)){
                    //2.获取MyTest注解的index值
                    int index1 = o1.getAnnotation(MyTest.class).value();
                    int index2 = o2.getAnnotation(MyTest.class).value();

                    //3.用这两个index值做比较
                    return index2 - index1;

                }
                return 0;
            }
        });
        //5.遍历数组
        for (Method m : ms) {
            if (m.isAnnotationPresent(MyTest.class)) {
                //执行此方法
                m.invoke(o);
            }
        }

    }
}

注解类:

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 {
    //定义一个属性index
    int value() ;
}

Student类:

public class Student {
    @MyTest(1)
    public void show2(){
        System.out.println("show2() index = 1");
    }
    @MyTest(2)
    public void show1(){
        System.out.println("show1() index = 2");
    }

    public void test1(){
        System.out.println("test1()");
    }
    @MyTest(3)
    public void test2(){
        System.out.println("test2() index = 3");
    }


}
代码图解

在这里插入图片描述


版权声明:本文为weixin_45144691原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。