注解--java高级技术

2021/4/20 1:25:12

本文主要是介绍注解--java高级技术,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!

注解的概念

/**
     目标:注解的概念。

     注解:
            用在类上,方法上,成员变量,构造器,...上对成分进行编译约束,标记等操作的。
            注解是JDK1.5的新特性。
            注解相当一种标记,是类的组成部分,可以给类携带一些额外的信息。
            注解是给编译器或JVM看的,编译器或JVM可以根据注解来完成对应的功能。

     注解作用:
            1.标记。
            2.方法重写约束 @Override
            3.函数式接口约束。 @FunctionalInterface.
            4.现今最牛逼的框架技术多半都是在使用注解和反射。都是属于框架的底层基础技术。

     我们之前用的注解都是别人写好的,今天我们自己来定义一下注解。

 */
public class AnnotationDemo01 {

}

@FunctionalInterface
interface A{
    void test();
}

自定义注解

/**

 目标:我们之前都是用别人写好的注解,今天我们自己来做注解。

 自定义注解的格式:
     修饰符 @interface 注解名{
          // 注解属性
     }

  小结:
        自定义注解用@interface关键字。
        使用注解的格式:@注解名称。
        注解默认可以标记很多地方。
 */
@Book
@MyTest
public class MyBook {
    @Book
    @MyTest
    private MyBook(){

    }
    @Book
    @MyTest
    public static void main(@MyTest String[] args) {
        @MyTest
        @Book
        int age = 12;
    }
}

@interface Book{
}

@interface MyTest{

}

注解的属性

/**
     目标:注解的属性:

     属性的格式
            - 格式1:数据类型 属性名();
            - 格式2:数据类型 属性名() default 默认值;

     属性适用的数据类型:
            八种数据数据类型(int,short,long,double,byte
             ,char,boolean,float)
            String,Class
            以上类型的数组形式都支持

     小结:
        注解可以有属性,属性名必须带()
        在用注解的时候,属性必须赋值,除非这个属性有默认值!!
 */
@MyBook(name="《精通Java基础》",authors = {"播仔","Dlei","播妞"} , price = 99.9 )
public class AnnotationDemo01 {
    @MyBook(name="《精通MySQL数据库入门到删库跑路》",authors = {"小白","小黑"} ,
            price = 19.9 , address = "北京")
    public static void main(String[] args) {

    }
}

// 自定义一个注解
@interface MyBook{
    String name();
    String[] authors(); // 数组
    double price();
    String address() default "广州";
}

注解的特殊属性_value

/**
    目标:注解的特殊属性名称:value
        value属性,如果只有一个value属性的情况下,
        使用value属性的时候可以省略value名称不写!!

        但是如果有多个属性,且多个属性没有默认值,那么value是不能省略的。
 */
//@Book(value = "/deleteBook.action")
//@Book("/deleteBook.action")
//@Book(value = "/deleteBook.action" , age = 12)
//@Book("/deleteBook.action")
public class AnnotationDemo01{
}

@interface Book{
    String value();
    int age() default 10;
}

元注解

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

/**

     目标:元注解

     元注解是sun公司提供的。
     元注解是用在自定义注解上的注解。
     元注解是用来注解自定义注解的。

     元注解有两个:
         @Target:约束自定义注解只能在哪些地方使用,
             -- 但是默认的注解可以在类,方法,构造器,成员变量,... 使用。

         @Retention:申明注解的生命周期
             -- 申明注解的作用范围:编译时,运行时。

     @Target
          * 作用:用来标识注解使用的位置,如果没有使用该注解标识,则自定义的注解可以使用在任意位置。
          * 可使用的值定义在ElementType枚举类中,常用值如下
             TYPE,类,接口
             FIELD, 成员变量
             METHOD, 成员方法
             PARAMETER, 方法参数
             CONSTRUCTOR, 构造器
             LOCAL_VARIABLE, 局部变量

     @Retention
         作用:用来标识注解的生命周期(有效存活范围)
          * 可使用的值定义在RetentionPolicy枚举类中,常用值如下
          * SOURCE:注解只作用在源码阶段,生成的字节码文件中不存在
          * CLASS:注解作用在源码阶段,字节码文件阶段,运行阶段不存在,默认值.
          * RUNTIME:注解作用在源码阶段,字节码文件阶段,运行阶段(开发常用)
     小结:
        @Target约束自定义注解可以标记的范围。
        @Retention用来约束自定义注解的存活范围。
 */
public class AnnotationDemo01{
    // @MyTest
    private String name;

    @MyTest
    public static void main( String[] args) {
    }

    @MyTest
    public void testRun(){

    }
}

//@Target({ElementType.METHOD , ElementType.FIELD}) // 申明只能注解方法和成员变量!
@Target(ElementType.METHOD ) // 申明只能注解方法
@Retention(RetentionPolicy.RUNTIME) // 申明注解从写代码一直到运行还在,永远存活!!
@interface MyTest{
}

注解的解析

import org.junit.Test;

import java.lang.annotation.*;
import java.lang.reflect.Method;
import java.util.Arrays;

/**
     目标:注解的解析

     我们会使用注解注释一个类的成分,那么就设计到要解析出这些注解的数据。
     开发中经常要知道一个类的成分上面到底有哪些注解,注解有哪些属性数据,这都需要进行注解的解析。

     与注解解析相关的接口
          1. Annotation: 注解类型,该类是所有注解的父类。注解都是一个Annotation的对象
          2. AnnotatedElement:该接口定义了与注解解析相关的方法
            所有的类成分Class, Method , Field , Constructor:都实现了AnnotatedElement接口
            他们都拥有解析注解的能力:
             a.Annotation[]	getDeclaredAnnotations()
                获得当前对象上使用的所有注解,返回注解数组。
             b.T getDeclaredAnnotation(Class<T> annotationClass)
                 根据注解类型获得对应注解对象
             c.boolean isAnnotationPresent(Class<Annotation> annotationClass)
                判断当前对象是否使用了指定的注解,如果使用了则返回true,否则false

     解析注解数据的原理
         * 注解在哪个成分上,我们就先拿哪个成分对象。
         * 比如注解作用成员方法,则要获得该成员方法对应的Method对象,再来拿上面的注解
         * 比如注解作用在类上,则要该类的Class对象,再来拿上面的注解
         * 比如注解作用在成员变量上,则要获得该成员变量对应的Field对象,再来拿上面的注解

     需求:(了解即可)
         1. 定义注解Book,要求如下:
             - 包含属性:String value()   书名
             - 包含属性:double price()  价格,默认值为 100
             - 包含属性:String[] authors() 多位作者
             - 限制注解使用的位置:类和成员方法上
             - 指定注解的有效范围:RUNTIME
         2. 定义BookStore类,在类和成员方法上使用Book注解
         3. 定义AnnotationDemo01测试类获取Book注解上的数据
 */
public class AnnotationDemo01 {
    @Test
    public void parseClass(){
        // 1.定位Class类对象
        Class c = BookStore.class ;
        // 2.判断这个类上是否使用了某个注解
        if(c.isAnnotationPresent(Book.class)){
            // 3.获取这个注解对象
            Book book = (Book) c.getDeclaredAnnotation(Book.class);
            System.out.println(book.value());
            System.out.println(book.price());
            System.out.println(Arrays.toString(book.authors()));
        }
    }

    @Test
    public void parseMethod() throws Exception {
        // 1.定位Class类对象
        Class c = BookStore.class ;
        // 2.定位方法对象
        Method run = c.getDeclaredMethod("run");
        // 3.判断这个方法上是否使用了某个注解
        if(run.isAnnotationPresent(Book.class)){
            // 3.获取这个注解对象
            Book book = (Book) run.getDeclaredAnnotation(Book.class);
            System.out.println(book.value());
            System.out.println(book.price());
            System.out.println(Arrays.toString(book.authors()));
        }
    }
}

@Book(value = "《Java基础到精通》" , price = 99.5 , authors = {"波仔","波妞"})
class BookStore{
    @Book(value = "《Mybatis持久层框架》" , price = 199.5 , authors = {"dlei","播客"})
    public void run(){
    }
}

@Target({ElementType.TYPE,ElementType.METHOD}) // 类和成员方法上使用
@Retention(RetentionPolicy.RUNTIME) // 注解永久存活
@interface Book{
    String value();
    double price() default 100;
    String[] authors();
}

自定义注解模拟写一个Junit框架的基本使用

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

/**
    目标:自定义注解模拟写一个Junit框架的基本使用。

    需求:定义若干个方法,只要加了MyTest注解,
          就可以被自动触发执行。

    分析:
        (1)定义一个自定义注解MyTest.
                -- 只能注解方法。
                -- 存活范围一直都在。
        (2)定义若干个方法,只要有@MyTest注解的方法就能被触发执行!!
             没有这个注解的方法不能执行!!
    小结:
        注解和反射可以配合解决一些框架思想
        注解可以实现标记的成分做特殊处理!!
 */
public class TestDemo{
    @MyTest
    public void test01(){
        System.out.println("===test01===");
    }

    public void test02(){
        System.out.println("===test02===");
    }

    @MyTest
    public void test03(){
        System.out.println("===test03===");
    }

    @MyTest
    public void test04(){
        System.out.println("===test04===");
    }
    public static void main(String[] args) throws Exception {
        TestDemo t = new TestDemo();
        // 模拟测试类的启动按钮,实现有注解标记的方法就要触发执行。
        // 1.得到类对象
        Class c = TestDemo.class;
        // 2.获取类中全部方法对象
        Method[] methods = c.getDeclaredMethods();
        // 3.遍历全部方法,有注解就触发执行
        for (Method method : methods) {
            if(method.isAnnotationPresent(MyTest.class)){
                // 触发此方法执行。
                method.invoke(t);
            }
        }
    }
}

@Target(ElementType.METHOD) // 只能注解方法!
@Retention(RetentionPolicy.RUNTIME) // 一直都活着
@interface MyTest{
}


这篇关于注解--java高级技术的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!


扫一扫关注最新编程教程