时间: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);
    }

}

JDK1.5新特性之注解的更多相关文章

  1. JDK1.7新特性(2):异常和可变长参数处理

    异常 jdk1.7对try--catch--finally的异常处理模式进行了增强,下面我们依次来看增强的方面. 1. 为了防止异常覆盖,给Throwable类增加了addSuppressed方法,可 ...

  2. JDK1.8新特性(一) ----Lambda表达式、Stream API、函数式接口、方法引用

    jdk1.8新特性知识点: Lambda表达式 Stream API 函数式接口 方法引用和构造器调用 接口中的默认方法和静态方法 新时间日期API default   Lambda表达式     L ...

  3. JDK1.8新特性之(三)--函数式接口

    在上一篇文章中我们介绍了JDK1.8的新特性有以下几项. 1.Lambda表达式 2.方法引用 3.函数式接口 4.默认方法 5.Stream 6.Optional类 7.Nashorm javasc ...

  4. JDK1.7新特性

    jdk1.7新特性 1 对集合类的语言支持: 2 自动资源管理: 3 改进的通用实例创建类型推断: 4 数字字面量下划线支持: 5 switch中使用string: 6 二进制字面量: 7 简化可变参 ...

  5. jdk1.6新特性

    1.Web服务元数据 Java 里的Web服务元数据跟微软的方案基本没有语义上的区别,自从JDK5添加了元数据功能(Annotation)之后,SUN几乎重构了整个J2EE体 系, 由于变化很大,干脆 ...

  6. Python3新特性 类型注解 以及 点点点

    Python3新特性 类型注解 以及 点点点 ... Python3 的新特性 Python 是一种动态语言,变量以及函数的参数是 不区分类型 的 在 函数中使用类型注解 相当于 给 形参的 类型 设 ...

  7. JDK1.8 新特性

    jdk1.8新特性知识点: Lambda表达式 函数式接口 *方法引用和构造器调用 Stream API 接口中的默认方法和静态方法 新时间日期API https://blog.csdn.net/qq ...

  8. JDK1.6新特性,WebService强化

    Web service是一个平台独立的,松耦合的,自包含的.基于可编程的web的应用程序,可使用开放的XML标准来描述.发布.发现.协调和配置这些应用程序,用于开发分布式的互操作的应用程序. Web ...

  9. JDK1.5新特性,基础类库篇,集合框架(Collections)

    集合框架在JDK1.5中增强特性如下: 一. 新语言特性的增强 泛型(Generics)- 增加了集合框架在编译时段的元素类型检查,节省了遍历元素时类型转换代码量. For-Loop循环(Enhanc ...

随机推荐

  1. 【译】.NET 对象分配工具

    随着 Visual Studio 16.10 的发布,性能分析器又有了一个新的分析引擎,.NET 对象分配工具是第一个加入的工具.这为该工具提供了一些新特性,并显著提高了 perf 性能.在你的 C# ...

  2. 基于IDEA的JAVA开发[第一集]:在Linux上安装IDEA

    1,因为买了荣耀的magicbook pro 锐龙版,系统是Linux,以后打算直接在Linux上开发.本来熟悉Myeclipse,下载了Myeclipse2017 for Linux,但是安装中出现 ...

  3. AI开发者十问:10分钟了解AI开发的基本过程

    摘要:从AI开发模型.框架.工具,到提升开发效率的学习办法,为AI开发者逐一解答. 本文分享自华为云社区<10分钟了解AI开发的基本过程>,作者:简单坚持. 1.AI开发究竟在开发什么? ...

  4. C++第四十六篇 -- C++将int转换成宽字符串

    int rate = 60; int score = 80 TCHAR Temp[64] = TEXT(""); _stprintf_s(Temp, TEXT("pass ...

  5. 开源与Saas,如何选择软件?

    随着云计算的发展和普及,在云上使用软件已经成为了主流,为了帮助广大用户理解,我在这里对云上软件的三种主要形态以及如何做出选择做一个简单的分析. 开源免费软件 绝大部分开源软件都是免费的,免费的出发点有 ...

  6. 解决ModuleNotFoundError: No module named 'pip'问题

    Python学习遇到小问题:ModuleNotFoundError: No module named 'pip' 今天想要装一下第三方库exifread的时候发现cmd窗口下无法执行pip命令,想了想 ...

  7. linux中的防火墙netfilter iptables

    目录 一.Linux防火墙基础 1.1 ptables的表.链结构 1.2 数据包控制的匹配流程 二.编写防火墙规则 1.iptables的安装 2.1 基本语法.控制类型 一般在生产环境中设置网络型 ...

  8. [解决方案]docker: Error response from daemon: OCI runtime create failed

    错误原因 在新服务器上安装好docker后,发现无法运行,经常一顿搜索后,发现是docker安装的版本过高,最新版本docker-18.06 的核心好像没有经过充分的测试就发布了. 导致一运行,就提示 ...

  9. 算法竞赛中的常用JAVA API :HashMap 和 TreeMap(转载)

    算法竞赛中的常用JAVA API :HashMap 和 TreeMap 摘要 本文主要介绍Map接口下的HashMap和TreeMap. HashMap HashMap是基于哈希表的 Map 接口的实 ...

  10. 超详细 Java 15 新功能介绍

    点赞再看,动力无限.微信搜「程序猿阿朗 」,认认真真写文章. 本文 Github.com/niumoo/JavaNotes 和 未读代码博客 已经收录,有很多知识点和系列文章. Java 15 在 2 ...