19_注解

文章目录

  • 注解
    • 注解的作用
    • 注解的语法
    • 注解的使用
  • 元注解
  • 注解处理器
    • 案例
  • 注解VS配置文件
  • 注解的应用

注解

  • Annotation是代码里的特殊标记,这些标记可以在编译、类加载、运行时被读取,并执行相应的处理
  • 可以把Annotation理解为一个标签
  • 注解是不允许继承

注解的作用

  • 通过使用Annotation,程序开发人员可以在不改变原有逻辑的情况下,在源文件嵌入一些补充信息
  • Annotation就像修饰符一样被使用,可用于修饰构造器方法成员变量参数…,这些信息被存储在Annotation的“属性名=属性值”对中。

注解 VS 注释

  • 相同点
    • 都是用来传递额外信息的
  • 不同点
    • 注解可以参与编译,注释不行
    • 注解有使用范围,注释没有(想咋写咋写)
    • 注解作为一种数据类型,跟class interface具有同等地位

注解的语法

权限修饰符 @interface 注解名字{
    // 注解体定义
    属性类型 属性名();
    属性类型 属性名();
    属性类型 属性名();
    ......
}

属性类型:
基本数据类型
String类型
Class类型
注解类型
枚举类型
以及以上类型的数组形式

eg:

public @interface MyAnnotation {
    int a1();

    double a2();

    String a3();

    Class a4();

    MyAnnotation2 a5();
    
    String[] str();
    
    Season a6();
}

@interface MyAnnotation2{
    
}

enum Season{
    SPRING,
    SUMMER,
    AUTUMN,
    WINTER
}

注解的使用

@注解名(属性1=属性值,属性2=属性值)

注意事项:

  • 每个属性都要赋值

  • 可以不赋值,但是要有默认值, default

  • 数组形式赋值 {}

  • 如果只有1个属性, 名字叫value, 可以简化赋值

  • 如果属性类型是引用类型, 不能是null

eg:


public class Demo {
    public static void main(String[] args) {

    }

    @MyAnno0(hobby = {"football", "basketball", "tennis"})
    @MyAnno1("zs")
    public static void func() {

    }
}

@interface MyAnno0 {
    // 注解体
    int age() default 0;

    String name() default "zs";

    String[] hobby();
}

@interface MyAnno1 {
    // 注解体
    String value();
}


元注解

  • 描述注解的注解(注解的注解)
  • 元数据 meta data

常用元注解:

  • @Retention元注解,来定义我们自己定义的注解的保留级别

    • RetentionPolicy.RUNTIME

    • RetentionPolicy.CLASS 默认

    • RetentionPolicy.SOURCE

  • @Target元注解,注解可以作用的目标

    • 对于注解而言,可以作用的目标:

        1. 整个类 ElementType.TYPE
        1. 成员变量 ElementType.FIELD
        1. 构造方法 ElementType.CONSTRUCTOR
        1. 成员方法 ElementType.METHOD

eg:

19_注解_第1张图片


注解处理器

eg:


public class Demo {
    public static void main(String[] args) 
            throws ClassNotFoundException, NoSuchMethodException {
        // 获取字节码文件对象
        Class<?> c = Class.forName("com.csdn.Demo");

        // 得到方法对象
        Method loginMethod = c.getDeclaredMethod("login");

        // 判断方法上面是否使用注解了
        boolean annotationPresent = loginMethod.isAnnotationPresent(Login.class);

        if(annotationPresent){
            // 获取注解实例
            Login loginAnnotation = loginMethod.getAnnotation(Login.class);
            // 获取注解信息
            String password = loginAnnotation.password();
            String name = loginAnnotation.name();
            // 打印
            System.out.println("password = " + password);
            System.out.println("name = " + name);
        }
        else{
            System.out.println("未使用注解");
        }
    }
    @Login
    public static void login(){

    }
}

// 定义注解
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
@interface Login{
    // 属性值
    String name() default "admin";

    String password() default "admin";
}

案例

定义2个注解 :

  • AgeLimit 属性 maxAge minAge

  • NameLimit 属性 length

定义学生类Student 年龄18-25之间 名字长度不超过5

eg:


StudentFactory自己定义的类:
public class StudentFactory {
    static Class studentUtils;

    static {
        try {
            studentUtils = Class.forName("com.cskaoyan.Demo0112.Student");
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }

    // 提供一个获取学生对象的方法
    public static Student getInstance(String name, int age)
            throws NoSuchFieldException, NoSuchMethodException,
            InvocationTargetException,
            InstantiationException, IllegalAccessException {
        // 通过字节码文件获取对象

        // 判断名字
        judgeName(name);

        // 判断年龄
        judgeAge(age);

        // 获取构造方法
        Constructor declaredConstructor = 
        studentUtils.getDeclaredConstructor(String.class, int.class);

        // 破解
        declaredConstructor.setAccessible(true);

        // newInstance 创建对象
        Student student = (Student) declaredConstructor.newInstance(name, age);

        // 最终返回一个学生对象
        return student;
    }

    private static void judgeAge(int age) throws NoSuchFieldException {
        // 获取age成员变量对象
        Field ageField = studentUtils.getDeclaredField("age");
        // 是否使用注解
        boolean annotationPresent = ageField.isAnnotationPresent(AgeLimit.class);
        if (annotationPresent) {
            // 获取注解实例
            AgeLimit ageLimit = ageField.getAnnotation(AgeLimit.class);
            // 拿到注解信息
            int min = ageLimit.minAge();
            int max = ageLimit.maxAge();
            // 是否在范围内
            if (age < min || age > max) {
                throw new IllegalArgumentException("age is illegal");
            }
        }
    }

    private static void judgeName(String name) throws NoSuchFieldException {
        // 获取name成员变量
        Field nameField = studentUtils.getDeclaredField("name");
        // 是否使用注解
        boolean annotationPresent = nameField.isAnnotationPresent(NameLimit.class);
        if (annotationPresent) {
            // 获取注解实例
            NameLimit namelimit = nameField.getAnnotation(NameLimit.class);
            // 拿到注解信息
            int length = namelimit.length();
            // 是否在范围内
            if (name.length() > length) {
                throw new IllegalArgumentException("name is illegal");
            }
        }
    }
}




main函数:
public class Demo {
    public static void main(String[] args)
            throws NoSuchFieldException, InvocationTargetException,
            NoSuchMethodException, InstantiationException,
            IllegalAccessException {
        StudentFactory.getInstance("zs",18);

        StudentFactory.getInstance("ww",1);
    }
}
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@interface AgeLimit{
    int maxAge() default 25;
    int minAge() default 18;
}

@interface NameLimit{
    int length();
}

class Student{
    @NameLimit(length = 5)
    String name;
    @AgeLimit
    int age;

    public Student(String name, int age) {
        this.name = name;
        this.age = age;
    }

    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}

注解VS配置文件

配置文件
优点:可配置,不用改源码。管理方便
缺点:不直观,开发效率低

注解
优点:直观开发效率高
缺点:硬编码,修改之后需要重新编译运行,难以和代码分开独立管理

注解的应用

SE :

  • @Test
  • @Override(提供一个额外的信息,方法是重写父类中的方法)
  • @Deprecated(提供一个额外的信息,方法过时了)
  • @FunctionalInterface

EE :

  • @WebService

框架

  • @AutoWired
  • @Service
  • @Mapping
  • @Data
  • @Parm

你可能感兴趣的:(JavaSE,java)