• JavaWeb【自定义注解】


     

    一。自定义注解(形体)

    情形一: 单一注解

      定义

    public @interface MyAnnotation {
        //定义注解属性:
        //属性类型 属性名() default 默认值;
        //String name() default "自定义名字"; 
        String name();
        int age() default 20;
        //注解属性类型:基本类型,String,Class,注解,枚举,和 前面几种类型的一维数组
        //Student student; error:The blank final field student may not have been initialized
    }

      使用:

    class Demo{
        //给注解赋值
        @MyAnnotation(name="段哥哥",sex="男")
        public void hello(){
            System.out.println("hello");
        }    
    }

    情形二:注解的嵌套

      定义

    public @interface MyAnnotation2 {
        String url() default "";
        MyAnnotation[] myAnnotations();
    }

      使用

    @MyAnnotation2(myAnnotations={@MyAnnotation(name="注解一",sex="女"),@MyAnnotation(name="注解二",sex="男")})
    class Demo2{
        @MyAnnotation2(myAnnotations={@MyAnnotation(name="注解一",sex="女"),@MyAnnotation(name="注解二",sex="男")})
        public void hello(){
            System.out.println("hello");
        }
    }

    情形三:特殊的注解属性value

      定义

    public @interface MyAnnotation3 {
        String name() default "name";
        String value() default "男";
    }

      使用

    class Demo3{
        @MyAnnotation3("who")
        public void hello(){}
    }

      ps:当使用注解没有指定给哪个属性赋值时,默认是value属性,所以上面的who就赋值给了value属性。

    情形四:数组类型的value

      定义

    public @interface MyAnnotation3 {
        String[] value() default ""; 
    }

      使用

    class Demo3{
        //给数组指定一个值
        @MyAnnotation3("a")
        public void hello(){
            
        }
        //给数组指定二个值    { }的使用
        @MyAnnotation3({"a","b"})
        public void hello2(){
            
        }
    }

      我们自定义的所有注解类型都是java.lang.Annotation接口的子类,既然子类,那么Annotation接口中的方法我们都可以使用


    二。注解的反射(灵魂)

    java.lang.reflect.AnnotatedElement 

    •   <T extends Annotation> T getAnnotation(Class<T> annotationClass):该方法获取指定Class类型的注解实例的引用
    •   Annotation[] getAnnotations():获取所有的注解,包含继承下来的
    •   Annotation[] getDeclaredAnnotations();获取自己直接使用的注解,不包含继承下来的
    •   boolean isAnnotaionPresent(Class<? extends Annotaion> annotionType):看看指定的注解在不在

      谁来调用这些方法,AnnotatedElement接口的实现类,有以下这几个AnnotatedElement的实现类:

    •   Class:表示一个类型
    •   Method:表示一个方法
    •   Field:表示一个字段
    •   Constructor:表示一个构造方法
    •   etc

    类的三种状态

      注解也就是类,只要是类就有三种状态

    一。SOURCE源代码(*.java)

      存在磁盘上

    二。CLASS字节码(*.class)

      存在磁盘上

    三。RUNTIME内存中的class

      从磁盘上加载到内存上。这就是类加载器所做的

      结论:在我们之前定义的注解,也就是类 处在CLASS字节码状态,存在于磁盘上

      验证上面的结论:

            Class class1=S.class;
            Method[] methods=class1.getMethods();
            for(Method m:methods){
                boolean flag=m.isAnnotationPresent(MyTest.class);
                System.out.println(m.getName()+"有没有"+flag);
            }
    View Code

      控制台输出的都为false

    注解的生命周期-元注解

      元注解:在注解上面定义的注解

      元注解的种类

      @Rentention

         作用;改变注解的存活范围

    @Documented
    @Retention(RetentionPolicy.RUNTIME)
    @Target(ElementType.ANNOTATION_TYPE)
    public @interface Retention {
        RetentionPolicy value();
    }
    public enum RetentionPolicy {
        /**
         * Annotations are to be discarded by the compiler.
         */
        SOURCE,
    
        /**
         * Annotations are to be recorded in the class file by the compiler
         * but need not be retained by the VM at run time.  This is the default
         * behavior.
         */
        CLASS,
    
        /**
         * Annotations are to be recorded in the class file by the compiler and
         * retained by the VM at run time, so they may be read reflectively.
         *
         * @see java.lang.reflect.AnnotatedElement
         */
        RUNTIME
    }
    RetentionPolicy

         使用:在注解的定义上,当我们运行下面代码,控制台上就会看到true了

            Class class1=S.class;
            Method[] methods=class1.getMethods();
            for(Method m:methods){
                boolean flag=m.isAnnotationPresent(MyTest.class);
                System.out.println(m.getName()+"有没有"+flag);
            }
    View Code

      但是单单使用了@Rentention只是改变了存活范围,该注解仅仅只能注解方法,要想在类上使用,我们需要在注解的位置上做限定

      @Target

         作用:注解应用的位置

    @Documented
    @Retention(RetentionPolicy.RUNTIME)
    @Target(ElementType.ANNOTATION_TYPE)
    public @interface Target {
        ElementType[] value();
    }
    public enum ElementType {
        /** Class, interface (including annotation type), or enum declaration */
        TYPE,
    
        /** Field declaration (includes enum constants) */
        FIELD,
    
        /** Method declaration */
        METHOD,
    
        /** Parameter declaration */
        PARAMETER,
    
        /** Constructor declaration */
        CONSTRUCTOR,
    
        /** Local variable declaration */
        LOCAL_VARIABLE,
    
        /** Annotation type declaration */
        ANNOTATION_TYPE,
    
        /** Package declaration */
        PACKAGE
    }
    ElementType

      @Documented:应用了该注解的注解的类,对应的文档中是否显示注解

      @Inherited:被注解的注解的类 的子类,会自动注解子类

      

      结论:仅仅定义注解只是定义了形体,如果想要发挥作用,就是需要反射,而反射所依赖的一些东西,需要元注解去注解


    三。注解的意义

      在开发中,通过一些xml配置来指挥程序的运行,

        缺点:开发不直观

        优点:避免硬编码

      注解是来替代xml作为配置用的

        优点:直观,开发简便,快速

        缺点:硬编码

  • 相关阅读:
    Java线程面试题 Top 50
    抽象类
    this和super的区别
    引用传递
    【代码】递归调用
    java异常
    抽象类 final
    sublime使用技巧
    zabbix表达式
    tcpdump
  • 原文地址:https://www.cnblogs.com/xingdongpai/p/5140951.html
Copyright © 2020-2023  润新知