• JavaSE学习笔记--Item1 注解Annotation


    从 JDK 5.0 開始, Java 添加了对元数据(MetaData) 的支持, 也就是 Annotation(注解)。


    什么是Annotation,以及注解的作用?

    三个主要的 Annotation:

    • @Override: 限定重写父类方法, 该注解仅仅能用于方法
    • @Deprecated: 用于表示某个程序元素(类, 方法等)已过时
    • @SuppressWarnings: 抑制编译器警告.

    上面的注解,在我们平时的编程中都是能够看见的。比方定义一个Parent类和一个MyIterface的接口。用Child的子类去继承Parent并实现MyInterface.就能够看到

    Parent

    public class Parent {
        public void m1(){
    
        }
        public void l1l1l1l1llll1ll1l1(){
    
        }
    }

    MyInterface

    public interface MyInterface {
        void m2();
    }

    Child
    这里写图片描写叙述

    Annotation 事实上就是代码里的特殊标记, 它用于替代配置文件,也就是说。传统方式通过配置文件告诉类怎样执行,有了注解技术后,开发者能够通过注解告诉类怎样执行。在Java技术里注解的典型应用是:能够通过反射技术去得到类里面的注解,以决定怎么去执行类。

    掌握注解技术的要点:

    • 怎样定义注解
    • 怎样反射注解。并依据反射的注解信息,决定怎样去执行类

    一、注解的基本知识

    1、怎样定义注解

    定义新的 Annotation 类型使用 @interface 关键字

    public @interface 注解的名称{}

    2、定义注解中的属性

    注解属性的作用:原来写在配置文件里的信息,能够通过注解的属性进行描写叙述。


    类型 属性名称() [default 默认值];

    Annotation 的属性声明方式:String name();
    属性默认值声明方式:String name() default “xxx”;
    特殊属性value:假设注解中有一个名称value的属性,那么使用注解时能够省略value=部分,如@MyAnnotation(“xxx"),可是出现多个属性时,那就应该要写上value值,这样比較明白。

    定义一个MyAnno1的注解。同一时候定义一个MyAnno2 ,MyAnno2 作为MyAnno1的一个属性。

    public @interface MyAnno2 {
        int num();
    }
    //全部定义的注解都是java.lang.annotation.Annotation的子类
    
    //定义注解
    public @interface MyAnno1 {
        String name() default "";//注解的属性
        int age() default 0;
    //  MyAnno2[] myann(); //属性还能够是注解。注解数组
        String [] value() default "";
    }

    使用自己定义的注解

    //使用自己定义的注解
    public class UseMyAnno1 {
    
    //  @MyAnno1(name = "abc", age = 19, myann = { @MyAnno2(num = 20),
    //          @MyAnno2(num = 200) }) //myann是一个注解数组。
    //  public void method() {
    //
    //  }
    
        //@MyAnno1("abc") 就是给注解的value属性赋值
        @MyAnno1(value={"def","ddd"},age=10)
        public void method() {
    
        }
    }

    特别注意:类型必须是基本类型、String、Class、注解类型、枚举及以上类型的一维数组。

    二、注解的反射

    1、 AnnotationElement 接口

    JDK 5.0 在 java.lang.reflect 包下新增了 AnnotationElement 接口, 该接口代表程序中能够接受凝视的程序元素,具有例如以下方法

    这里写图片描写叙述

    • T getAnnotation(Class clazz):得到指定的注解类型
    • Annotation[] getAnnotations():得到全部的注解类型
    • Annotation[] getDeclaredAnnotations():得到自己上面的直接的注解类型
    • boolean isAnnotationPresent(Class clazz):有没有指定的注解

    Class、Method、Field、Constructor等都实现了该接口。
    实例:编写一个自己的注解Anno1,在MyClass1中使用该注解,MyClass2继承MyClass1,这样,MyClass2也具有MyClass1上的注解,可是两者还是有区别的,看例如以下代码

    package com.itheima.other.metaanno;
    
    import java.lang.annotation.Documented;
    import java.lang.annotation.ElementType;
    import java.lang.annotation.Inherited;
    import java.lang.annotation.Retention;
    import java.lang.annotation.RetentionPolicy;
    import java.lang.annotation.Target;
    
    @Retention(RetentionPolicy.RUNTIME)
    @Target({ElementType.TYPE,ElementType.METHOD})
    @Documented
    @Inherited
    public @interface Anno1 {
    
    }
    

    MyClass1

    package com.itheima.other.metaanno;
    /**
     * 这是一个測试类
     * @author wzhting
     *
     */
    @Anno1
    public class MyClass1 {
    
    }

    MyClass2

    package com.itheima.other.metaanno;
    
    import java.lang.annotation.Annotation;
    
    public class MyClass2 extends MyClass1 {
        public static void main(String[] args) {
            Class clazz = MyClass2.class;
    //      Anno1 a1 = (Anno1) clazz.getAnnotation(Anno1.class);
    //      System.out.println(a1);
    
            Annotation ans[]  =  clazz.getDeclaredAnnotations();//获取直接存在的注解
            for(Annotation a:ans)
                System.out.println(a);
        }
    }
    

    比方:推断Object这个类上面有没有MyAnn1的注解

    Class clazz = Object.class;
    Boolean b = clazz.isAnnotationPresent(MyAnn1.class);

    2、注解的生命周期:

    2.1 AnnotatedElement元注解

    仅仅能用在注解上的注解,就是元注解。JDK中定义了例如以下元Annotation:

    • @Retention:

    @Retention: 仅仅能用于修饰一个 Annotation 定义, 用于指定该 Annotation 能够保留的, @Rentention 包括一个 RetentionPolicy 类型的成员变量, 通过这个变量指定域。

    1. RetentionPolicy.CLASS: 编译器将把注解记录在 class 文件里. 当执行 Java 程序时, JVM 不会保留注解. 这是默认值
    2. RetentionPolicy.RUNTIME:编译器将把凝视记录在 class 文件里. 当执行 Java 程序时, JVM 会保留注解. 程序能够通过反射获取该凝视
    3. RetentionPolicy.SOURCE: 编译器直接丢弃这样的策略的凝视

    这里写图片描写叙述

    • @Target:指示注解能用在何处
      ElementType:指定注解用于修饰类的哪个成员. @Target 包括了一个名为 value。类型为ElementType的成员变量。看源代码可知有TYPE (Class,Interface), FIELD, METHOD, PARAMETER, ANNOTATION_TYPE等声明常量。

    实例:自己定义注解类MyTest

    首先定义两个实体类,用于单元測试分别为PersonDaoImpl 和測试类PersonDaoImplTest
    PersonDaoImpl

    package com.itheima.dao.impl;
    
    public class PersonDaoImpl {
        public void add(){
            System.out.println("保存了");
        }
        public void del(){
            System.out.println("执行了删除");
        }
    }
    

    PersonDaoImplTest

    package com.itheima.dao.impl;
    
    import org.junit.Test;
    
    public class PersonDaoImplTest {
        private PersonDaoImpl dao = new PersonDaoImpl();
    
        //測试方法:必须是public的;没有返回值;没有參数
        @MyTest(timeout=1)//===>自己编写MyTest注解
        public void testAdd() throws InterruptedException{
    //      Thread.sleep(100);
            dao.add();
        }
        public void testDel(){
            dao.del();
        }
    }
    

    自己定义一个类MyTest,和JUnit的@Test类类似。

    package com.itheima.dao.impl;
    
    import java.lang.annotation.ElementType;
    import java.lang.annotation.Retention;
    import java.lang.annotation.RetentionPolicy;
    import java.lang.annotation.Target;
    
    @Retention(RetentionPolicy.RUNTIME)//编译时,JVM保留注解
    @Target(ElementType.METHOD)//使用于方法。
    
    public @interface MyTest {
        long timeout() default -1;//没有时间限制。单位是毫秒
    }
    

    反射注解的方法及属性(重点)
    通过反射技术,编写MyTestRunner 类,实现MyTest注解的功能。

    package com.itheima.dao.impl;
    
    import java.lang.reflect.InvocationTargetException;
    import java.lang.reflect.Method;
    
    public class MyTestRunner {
    
        public static void main(String[] args) throws Exception{
            test1();
        }
        //反射注解的属性
        private static void test2() throws IllegalAccessException,
                InvocationTargetException, InstantiationException {
            Class clazz = PersonDaoImplTest.class;
            Method ms[] = clazz.getMethods();
            for(Method m:ms){
                MyTest myTest = m.getAnnotation(MyTest.class);//假设当前方法上面没有@MyTest注解。返回的是null
                if(myTest!=null){
                    //执行该方法。推断是否超时
                    long time = System.currentTimeMillis();
                    m.invoke(clazz.newInstance(), null);
                    long actualUseTime = System.currentTimeMillis()-time;//实际耗时
                    //获取注解上配置的timeout属性的值
                    long planUserTime = myTest.timeout();
                    if(planUserTime>=0){
                        //说明用户指定了时间
                        if(actualUseTime>planUserTime)
                            throw new RuntimeException("超时");
                    }
                }
            }
        }
        //反射方法上面的注解
    
        private static void test1() throws IllegalAccessException,
                InvocationTargetException, InstantiationException {
            //得到測试类的字节码
            Class clazz = PersonDaoImplTest.class;
            //得到全部的方法
            Method ms[] = clazz.getMethods();
            //推断方法上面有没有叫做@MyTest的注解
            for(Method m:ms){
                boolean b = m.isAnnotationPresent(MyTest.class);
                System.out.println(m.getName()+":"+b);
            //假设有:调用该方法
                if(b)
                    m.invoke(clazz.newInstance(), null);
            }
        }
    
    /*  testAdd:true
        testDel:false
        wait:false
        wait:false
        wait:false
        equals:false
        toString:false
        hashCode:false
        getClass:false
        notify:false
        notifyAll:false*/
    
    }
    

    下面两个了解就可以。

    • @Documented:用于指定被该元 Annotation 修饰的 Annotation 类将被 javadoc 工具提取成文档.
    • @Inherited:被它修饰的 Annotation 将具有继承性.假设某个类使用了被 @Inherited 修饰的 Annotation, 则其子类将自己主动具有该注解

    三、servlet3.0 中的注解

    在servlet3.0以后,就能够採用注解的方式代替web.xml文件里的servlet映射了
    比方例如以下servlet

    package com.itheima.servlet;
    
    import java.io.IOException;
    import java.io.PrintWriter;
    import java.util.Enumeration;
    
    import javax.servlet.ServletConfig;
    import javax.servlet.ServletException;
    import javax.servlet.annotation.WebInitParam;
    import javax.servlet.annotation.WebServlet;
    import javax.servlet.http.HttpServlet;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    
    @WebServlet(value = { "/servlet/ServletDemo1", "/servlet/ServletDemo11" }, initParams = {
            @WebInitParam(name = "encoding", value = "UTF-8"),
            @WebInitParam(name = "XXX", value = "YYY") })
    public class ServletDemo1 extends HttpServlet {
    
        public void doGet(HttpServletRequest request, HttpServletResponse response)
                throws ServletException, IOException {
            response.setContentType("text/html;charset=UTF-8");
            PrintWriter out = response.getWriter();
            out.write("ServletDemo1<hr/>");
            ServletConfig cfg = getServletConfig();
            Enumeration e = cfg.getInitParameterNames();
            while(e.hasMoreElements()){
                String paramName = (String)e.nextElement();
                out.write(paramName+"="+cfg.getInitParameter(paramName)+"<br/>");
            }
        }
    
        public void doPost(HttpServletRequest request, HttpServletResponse response)
                throws ServletException, IOException {
            doGet(request, response);
        }
    
    }
    

    当然,在过滤器和监听器中,也一样能够採用注解的方法代替web.xml的配置。

  • 相关阅读:
    我所理解的三次握手
    网络舆情——初步了解
    【转载】位运算的密码
    【转载】基础排序算法简介
    【原创】关于hashcode和equals的不同实现对HashMap和HashSet集合类的影响的探究
    【原创】Java移位运算
    【原创】MapReduce计数器
    【原创】Hadoop机架感知对性能调优的理解
    【原创】一个复制本地文件到Hadoop文件系统的实例
    【转载】JAVA IO 流的总结
  • 原文地址:https://www.cnblogs.com/brucemengbm/p/7130640.html
Copyright © 2020-2023  润新知