• JDK1.5新特性之注解


    时间:2017-1-2 20:14

    ——注解的概述

        注释是给人看的,而注解是给程序(框架)看的。
        在Servlet3.0中可以使用注解来替代配置文件,开发者就不用再写配置文件了,而是写注解,然后Tomcat来读取注解。

        注解也是类,需要定义了才能使用。
        在Servlet3.0中又一个注解类是@WebServlet,然后我们就可以在Servlet中使用@WebServlet这个注解了,这个朱姐就是用来替代<servlet>,然后Tomcat会通过反射来读取注解中的信息。

     
    ——Java中的注解
     
        *   @Overrid:作用在方法上的注解,当方法不是重写父类的方法时会报错。
        *   @Deprecated:作用在方法上,标记该方法为作废方法(已过时)。
        *   @SuppressWarnings:作用在方法上,压制警告。
     
    ——定义注解类

        定义注解类不能使用class、enum和interface,而是使用@interface

        >   public @interface MyAnn{ }

    ——使用注解目标

        所有注解都是Annotation的子类。

        注解可以作用在:类(接口或枚举)、属性、方法、构造器、包、参数、局部变量

        *   定义注解类:框架的工作
        *   使用注解:我们的工作
        *   读取注解(反射):框架的工作

    ——注解的定义

        *   定义属性
            >   格式:类型 属性名()
            @interface MyAnno1{
                String name();
                int age();
            }

        *   使用注解时给属性赋值
            >   @MyAnno(name="zhangsan", age=20)

        *   注解属性的默认值
            >   int age() default 100;
            >   在使用注解时,可以不给带有默认值的属性赋值。

        *   名为value的属性的特权
            >   在使用注解时,如果只给名为value的属性赋值,那么可以不给出属性的名称而直接赋值,当存在其他属性时,必须加上“value=”。
            >   @MyAnno("zhangsan"):表示给value="zhangsan"赋值。

        *   注解属性的类型
            >   8种基本类型
            >   String类型
            >   枚举类型
            >   Class类型
            >   注解类型
            >   以上类型的一维数组类型

            >   定义:
                @MyAnno1{
                    int a();
                    String b();
                    MyEnum c();
                    Class d();
                    MyAnno2 e();
                    String f();
                }

            >   使用:
                @MyAnno1(
                    a=100,
                    b="zhangsan",
                    c=MyEnum.option,
                    d=String.class,
                    e=@MyAnno2(age=20,name="zhangsan"),
                    f={"123", "456"}
                )

    ——注解的作用目标限定以及保存策略限定

    1、目标限定
        让一个注解的作用目标只能在类上,而不能在方法上,这就叫作用目标的限定。

        在定义注解时,给注解添加注解,这个注解时@Target
        Target注解有一个属性:ElementType[] value(),这个属性是一个枚举类型。

        使用方法:
            @Target(value={ElementType.TYPE, ElementType.METHOD, ElementType/FIELD})
            @interface MyAnno{ }

    2、保留策略
        *   源代码文件(SOURCE)
            >   注解只在源代码中存在,当编译时就被忽略了(不能被反射)

        *   字节码文件(CLASS)
            >   注解在源代码中存在,编译时会把注解信息放到class文件中,但JVM在加载类时,会忽略注解。

        *   JVM中(RUNTIME)
            >   注解在源代码、字节码文件中存在,并且在JVM加载类时,会把注解加载到JVM内存中(它是唯一可以反射的注解)

        限定注解的保留策略:
            使用RetentionPolicy注解:
                @Retention(RetentionPolicy.RUNTIME)

    ——读取注解(反射)

    1、要求:
        注解的保留策略必须是RUNTIME

    2、反射注解需要从作用目标上反射
        *   类上的注解,需要使用Class来获取
        *   方法上的注解,需要用Method来返回
        *   构造器上的注解,需要用Constructor来获取
        *   成员上的注解,需要用Field来获取

    Class类方法概要:
        <T extends Annotation>  getAnnotation(Class<A> annotationClass)
            如果存在该元素的指定类型的注解,则返回这些注解,否则返回null。

        Annotation[]  getAnnotations()
            返回此元素上存在的所有注解。


    Method、Field、Constructor:
        这三个类都是AccessibleObject的子类。 

    AccessibleObject类方法概要:
        <T extends Annotation>  getAnnotation(Class<T> annotationClass)
            如果存在该元素的指定类型的注解,则返回这些注解,否则返回null。

        Annotation[]  getAnnotations()
            返回此元素上存在的所有注解。

        Annotation[]  getDeclaredAnnotations()
            返回直接存在于此元素上的所有注解。

    示例代码:
     
    import java.lang.annotation.Retention;
    import java.lang.annotation.RetentionPolicy;
    import java.lang.reflect.Field;
     
    import org.junit.Test;
     
    public class Demo {
        @Test
        public void fun1() {
            /*
             * 1、得到作用目标
             */
            Class<A> c = A.class;
            /*
             * 2、获取指定类型的注解
             */
            MyAnno1 myAnno1 = c.getAnnotation(MyAnno1.class);
     
            System.out.println(myAnno1.name() + ", " + myAnno1.age());
        }
     
        @Test
        public void fun2() throws Exception {
            /*
             * 1、得到作用目标
             */
            Class<A> c = A.class;
            // Field权限必须为public
            Field field = c.getField("name");
     
            /*
             * 2、获取指定类型的注解
             */
            MyAnno1 myAnno1 = field.getAnnotation(MyAnno1.class);
            System.out.println(myAnno1.name() + ", " + myAnno1.age());
        }
    }
     
    @MyAnno1(name = "zhangsan", age = 20)
    class A {
        @MyAnno1(name = "lisi", age = 21)
        public String name;
     
    }
     
    @Retention(RetentionPolicy.RUNTIME)
    @interface MyAnno1 {
        String name();
        int age();
    }
     
    ——反射泛型信息

        public Type getGenericSuperclass()
            返回表示此Class所表示的实体(类、接口、基本类型或void)的直接父类的Type。
            获取传递给父类的泛型信息。
            返回的类型是Type接口的子接口:ParameterizedType(参数化类型) == A<String>

        1、子类:得到当前类的Class对象:this.getClass()
        2、Class:得到当前类父类的参数化类型(A<String, Integer...>):Type  getGenericSuperclass(),因为返回值是ParameterizedType,所以需要强制类型转换。
        3、ParameterizedType:得到所有的类型参数<String, Integer...>:Type[]  getActualTypeArguments()
     
    示例代码:

    package demo2;
     
    import java.lang.reflect.ParameterizedType;
    import java.lang.reflect.Type;
     
    import org.junit.Test;
     
    public class Demo1 {
        @Test
        public void fun() {
            new B();
            new C();
        }
    }
     
    abstract class A<T> {
        public A() {
            /*
             * 在这里获取子类传递的泛型信息,得到一个Class对象
             */
     
            Class c = this.getClass(); // 得到子类的类型
     
            // 得到的type就是A<String>
            Type type = c.getGenericSuperclass();
     
            // 因为type的类型是ParameterizedType,所以需要强转
            ParameterizedType pType = (ParameterizedType) type;
     
            // 获取类参数,得到的是一个数组<String, Integer...>
            Type[] types = pType.getActualTypeArguments();
     
            // 得到String
            Class c2 = (Class) types[0];
     
            System.out.println(c2); // String或者Integer
     
            // 简写
            Class c3 = (Class) ((ParameterizedType) this.getClass().getGenericSuperclass()).getActualTypeArguments()[0];

            System.out.println(c3);
        }
    }
     
    class B extends A<String> {
     
    }
     
    class C extends A<Integer> {
     
    }  
     
     

    ——反射泛型和反射注解的应用案例


    User类:

    package demo2;
     
    @Table("tb_user") // 它的值表示当前类所对应的表
    public class User {
        @ID("u_id") // 表示当前属性对应的列名,而且说明这个字段是主键字段
        private String uid;
        @Column("username")
        private String username;
        @Column("password")
        private String password;

        @Test
        public void fun(){
            Class<User> c = User.class;
            Table a = c.getAnnotation(Table.class);
            System.out.println(a.value());
     
      Field f = c.getDeclaredField("uid");
      f.setAccessible(true);
      ID id = f.getAnnotation(ID.class);
      System.out.println(id.value());
        } 
    }
    ----------------------------------------------------------------------------------------------------------------------------

    Table注解:

    package demo2;
    @Retention(RetentionPolicy.RUNTIME)
    public @interface Table {
        String value();
    }
     


    ----------------------------------------------------------------------------------------------------------------------------

    ID注解:

    package demo2;
    @Retention(RetentionPolicy.RUNTIME)
    public @interface ID {
        String value();
    }


    ----------------------------------------------------------------------------------------------------------------------------

    Column注解:

    package demo2;
    @Retention(RetentionPolicy.RUNTIME)
    public @interface Column {
        String value();
    }
     
    ----------------------------------------------------------------------------------------------------------------------------

    BaseDAO:

    package demo2;
     
    import java.lang.reflect.Field;
    import java.lang.reflect.ParameterizedType;
    import java.util.List;

    -------------------------

    public class Demo2 {
        private QueryRunner qr = new TxQueryRunner();
     
        /*
         * 使用dbutils
         */
        public void addUser(User user) {
            String sql = "";
            Object[] params = {};
            qr.update(sql, params);
        }
     
        public void addCustomer(Customer customer) {
            String sql = "";
            Object[] params;
            qr.update(sql, params);
        }
    }

    -------------------------

    /**
     * 因为普通DAO有许多重复的工作
     * 所以可以考虑编写一个BaseDAO来完成重复操作
     * 功能与BaseServlet相似。
     * @author WYC
     *
     * @param <T>
     */
    class BaseDAO<T> {
        private QueryRunner qr = new TxQueryRunner();
        private Class<T> beanClass;
        private int length;
     
        public BaseDAO() {
            // 获取泛型参数,用于获得表名
            this.beanClass = (Class) ((ParameterizedType) this.getClass().getGenericSuperclass()).getActualTypeArguments()[0];
     
            // 获取属性个数,用于获得参数个数、参数值、参数列名
            Field[] fields = beanClass.getDeclaredFields();
            this.length = fields.length;
     
        }
     
        public void add(T bean) {
            // 可以将表名作为注解配置到类上,然后通过反射注解来获取配置的表名信息
            String sql = "insert into " + beanClass.getSimpleName() + " values(";
     
            // 指定参数个数
            for (int i = 0; i < this.length; i++) {
                if (i == length - 1) {
                    sql += "?)";
                } else {
                    sql += "?,";
                }
            }
     
            // 可以通过反射Field来获取参数值
            Object[] params = {/* 参数值是什么 */};
            qr.update(sql, params);
        }
     
        public void update(T bean) {
     
        }
     
        public void delete(String uuid) {
     
        }
     
        public T load(String uuid) {
            return null;
        }
     
        public List<T> findAll() {
            return null;
        }
    }

    -------------------------

    class UserDAO extends BaseDAO<User> {
        public void addUser(User user) {
            super.add(user);
        }
  • 相关阅读:
    Cause: java.sql.SQLIntegrityConstraintViolationException: Duplicate entry '1288372549423476738' for key 'PRIMARY'
    环形数组循环
    less命令
    ln命令
    Vue中$refs的理解
    cut命令
    除数博弈
    find命令
    file命令
    最长公共前缀
  • 原文地址:https://www.cnblogs.com/wwwwyc/p/6375382.html
Copyright © 2020-2023  润新知