java注解的使用

chenweicool 2020-11-11 17:58:02
java 使用 博客园 注解


java中注解的使用

1.说再前面

使用注解开发的好处

1.使代码更加干净易读,易于维护修改。比如,以前使用spring的开发,都是基于xml文件实现了统一的配置管理,但是缺点也是显而易见的,就是随着项目的越来越大,xml文件会变得越来越复杂,维护成本也会越来越高。使用注解就可以提供更大的便捷性,易于维护修改。

2 可以实现代码的类型检查,特别是在编译器的角度实现一些类型检查,比如预检查(@Override)和抑制警告(@SuppressWarnings)等。

3 自定义注解,作为额外信息的载体,存储有关程序的额外信息

2 注解的分类以及使用

​ Java注解是附加在代码中的一些元信息,用于编译和运行时进行解析和使用,起到说明、配置的功能。

注解不会影响代码的实际逻辑,仅仅起到辅助性的作用。包含在java.lang.annotation包中。注解的定义类似于接口的定义,使用@interface来定义,定义一个方法即为注解类型定义了一个元素,方法的声明不允许有参数或throw语句,返回值类型被限定为原始数据类型、字符串String、Class、enums、注解类型,或前面这些的数组,方法可以有默认值。注解并不直接影响代码的语义,但是他可以被看做是程序的工具或者类库。它会反过来对正在运行的程序语义有所影响。注解可以从源文件、class文件或者在运行时通过反射机制多种方式被读取。

一般来说,注解一般分为三种类型: 元注解,标准注解,自定义注解

2.1 元注解

元注解是专职负责注解其他注解,主要是标明该注解的使用范围,生效范围。我们是不能改变它的,只能用它来定义我们自定义的注解。

包括 @Retention @Target @Document @Inherited四种。(java.lang.annotation中提供,为注释类型)。

注解 说明
@Target 定义注解的作用目标,也就是可以定义注解具体作用在类上,方法上,还是变量上
@Retention 定义注解的保留策略。RetentionPolicy.SOURCE:注解仅存在于源码中,在class字节码文件中不包含;RetentionPolicy.CLASS:默认的保留策略,注解会在class字节码文件中存在,但运行时无法获得;RetentionPolicy.RUNTIME:注解会在class字节码文件中存在,在运行时可以通过反射获取到。
@Document 说明该注解将被包含在javadoc中
@Inherited 说明子类可以继承父类中的该注解

Target类型主要依赖于ElementType这个类型,具体的类型如下:

Target类型 说明
ElementType.TYPE 接口、类、枚举、注解
ElementType.FIELD 字段、枚举的常量
ElementType.METHOD 方法
ElementType.PARAMETER 方法参数
ElementType.CONSTRUCTOR 构造函数
ElementType.LOCAL_VARIABLE 局部变量
ElementType.ANNOTATION_TYPE 注解
ElementType.PACKAGE

2.2 标准注解

Java标准注解提供了三个,定义在java.lang中的注解,我认为这三个注解的作用更多的是一种注释

  • @Override 表示当前方法覆盖父类中的方法。

  • @Deprecated 标记一个元素为已过期,避免使用

支持的元素类型为:CONSTRUCTOR, FIELD, LOCAL_VARIABLE, METHOD, PACKAGE, PARAMETER, TYPE

  • @SuppressWarnings 不输出对应的编译警告

    一个简单的使用demo:

    @SuppressWarnings(value = {"unused", "rawtypes"})
    public class Children extends Parent{
    @Override
    public void work() {
    System.out.println("我是一个被重写的方法");
    }
    @Deprecated
    public void play(){
    System.out.println("这个方法不推荐使用了");
    }
    }
    

2.3 自定义注解实现一个sql语句的拼接

需要注意的方面:注解的定义类似于接口的定义,使用@interface来定义,定义一个方法即为注解类型定义了一个元素,方法的声明不允许有参数或throw语句,返回值类型被限定为原始数据类型、字符串String、Class、enums、注解类型,或前面这些的数组,方法可以有默认值。

自定义注解一般可以分为三步: 定义注解,使用注解,读取注解

定义注解

@Target(ElementType.TYPE) //注解加载类上
@Retention(RetentionPolicy.RUNTIME) // 运行时读取注解
public @interface Table {
String value();
}
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
[email protected] UserFiled {
String name();
String type();
int length();
}

使用注解

// 将自定义的注解加在用户上,实现一个表的映射
@Table(value = "user_table")
public class User {
@UserFiled(name = "user_id",type = "int",length = 8)
private int userId;
@UserFiled(name = "user_name",type = "varchar",length = 16)
private String userName;
@UserFiled(name = "password",type = "varchar",length = 16)
private String password;
public int getUserId() {
return userId;
}
public void setUserId(int userId) {
this.userId = userId;
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
}

读取注解的内容

/**
* 读取注解中的值
*/
public class GetUser {
public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException {
Class userClass = Class.forName("annocation.blog.User");
// 读取类上的注解
Table table = (Table) userClass.getAnnotation(Table.class);
System.out.println(table.value());
// 读取属性上注解
Field userId = userClass.getDeclaredField("userId");
UserFiled userFiledId = userId.getAnnotation(UserFiled.class);
System.out.println(userFiledId.length() + "----" + userFiledId.type() + "-----" + userFiledId.name());
Field userName = userClass.getDeclaredField("userName");
UserFiled userFiledName = userName.getAnnotation(UserFiled.class);
System.out.println(userFiledName.length()+"----"+userFiledName.type()+"----"+userFiledName.name());
Field password = userClass.getDeclaredField("password");
UserFiled userFiledPassword = password.getAnnotation(UserFiled.class);
System.out.println(userFiledPassword.name() + "-----" + userFiledPassword.type() + "-----" + userFiledPassword.length());
// 拼接一个sql语句
String name = "chenwei";
String sql ="select * from" + table.value()+"where"+userFiledName.name()+"="+name;
}
}

结果:

user_table
user_id----int-----8
user_name----varchar----16
password-----varchar-----16

自定义注解的实现过程:

1,定义注解

2,使用注解,根据自己定义的注解来达到一些目的,本例中,就是使用注解来完成数据库表和实体类的映射关系

3 读取注解的内容,也是比较重要的一部分,核心还是利用了反射的思想,得到使用注解的这个类,根据类中的getAnnotion的方法得到定义的注解,获得注解上的值。

3 注解的实现的原理

注解的实现的原理很大的一部分是基于反射实现。

​ 反射可以获取到Class对象,进而获取到Constructor、Field、Method等实例,点开源码结构发现Class、Constructor、Field、Method等均实现了AnnotatedElement接口,AnnotatedElement接口的方法如下

// 判断该元素是否包含指定注解,包含则返回true
boolean isAnnotationPresent(Class<? extends Annotation> annotationClass)
// 返回该元素上对应的注解,如果没有返回null
<T extends Annotation> T getAnnotation(Class<T> annotationClass);
// 返回该元素上的所有注解,如果没有任何注解则返回一个空数组
Annotation[] getAnnotations();
// 返回指定类型的注解,如果没有返回空数组
T[] getAnnotationsByType(Class<T> annotationClass)
// 返回指定类型的注解,如果没有返回空数组,只包含直接标注的注解,不包含inherited的注解
T getDeclaredAnnotation(Class<T> annotationClass)
// 返回指定类型的注解,如果没有返回空数组,只包含直接标注的注解,不包含inherited的注解
T[] getDeclaredAnnotationsByType
// 返回该元素上的所有注解,如果没有任何注解则返回一个空数组,只包含直接标注的注解,不包含inherited的注解
Annotation[] getDeclaredAnnotations();

通过一个实例再次说明一下注解的使用过程:

定义注解

@Documented
@Target({ElementType.TYPE, ElementType.FIELD,ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnotaion {
String getValue() default "this is myAnntaion";
int order() default 0;
}

使用注解

@MyAnnotaion(getValue = "annotation on class")
public class Demo {
@MyAnnotaion(getValue = "annotation on filed")
public String name;
@MyAnnotaion(getValue = "annotation on method")
public void hello(){
}
@MyAnnotaion
public void defaultMethod(){
}
}

利用反射读取注解中的值。

public class TestDemo {
public static void main(String[] args) throws NoSuchFieldException, NoSuchMethodException {
/**
* 获取类上的注解
*/
Class<Demo> demoClass = Demo.class;
Annotation[] annotaion = demoClass.getAnnotations();
printAnnotation(annotaion);
/**
* 读取成员变量上的注解
*/
Field name = demoClass.getField("name");
Annotation[] getOnFiled = name.getAnnotations();
printAnnotation(getOnFiled);
/**
* 读取方法上的注解
*/
Method hello = demoClass.getMethod("hello", null);
MyAnnotaion onMethod = hello.getAnnotation(MyAnnotaion.class);
System.out.println(onMethod.getValue());
/**
* 获取默认方法上的注解
*/
Method defaultMethod = demoClass.getMethod("defaultMethod", null);
MyAnnotaion onDefaultMethod = defaultMethod.getAnnotation(MyAnnotaion.class);
System.out.println(onDefaultMethod.getValue());
}
public static void printAnnotation(Annotation... annotations) {
for (Annotation annotation : annotations) {
System.out.println(annotation);
}
}
}

运行结果

@annocation.MyAnnotaion(getValue=annotation on class, order=0)
@annocation.MyAnnotaion(getValue=annotation on filed, order=0)
annotation on method
this is myAnntaion

参考资料:

http://blog.kimzing.com/java/Java注解入门到精通-学这一篇就够了/

《java编程思想》

版权声明
本文为[chenweicool]所创,转载请带上原文链接,感谢
https://www.cnblogs.com/chentang/p/13959831.html

  1. 【计算机网络 12(1),尚学堂马士兵Java视频教程
  2. 【程序猿历程,史上最全的Java面试题集锦在这里
  3. 【程序猿历程(1),Javaweb视频教程百度云
  4. Notes on MySQL 45 lectures (1-7)
  5. [computer network 12 (1), Shang Xuetang Ma soldier java video tutorial
  6. The most complete collection of Java interview questions in history is here
  7. [process of program ape (1), JavaWeb video tutorial, baidu cloud
  8. Notes on MySQL 45 lectures (1-7)
  9. 精进 Spring Boot 03:Spring Boot 的配置文件和配置管理,以及用三种方式读取配置文件
  10. Refined spring boot 03: spring boot configuration files and configuration management, and reading configuration files in three ways
  11. 精进 Spring Boot 03:Spring Boot 的配置文件和配置管理,以及用三种方式读取配置文件
  12. Refined spring boot 03: spring boot configuration files and configuration management, and reading configuration files in three ways
  13. 【递归,Java传智播客笔记
  14. [recursion, Java intelligence podcast notes
  15. [adhere to painting for 386 days] the beginning of spring of 24 solar terms
  16. K8S系列第八篇(Service、EndPoints以及高可用kubeadm部署)
  17. K8s Series Part 8 (service, endpoints and high availability kubeadm deployment)
  18. 【重识 HTML (3),350道Java面试真题分享
  19. 【重识 HTML (2),Java并发编程必会的多线程你竟然还不会
  20. 【重识 HTML (1),二本Java小菜鸟4面字节跳动被秒成渣渣
  21. [re recognize HTML (3) and share 350 real Java interview questions
  22. [re recognize HTML (2). Multithreading is a must for Java Concurrent Programming. How dare you not
  23. [re recognize HTML (1), two Java rookies' 4-sided bytes beat and become slag in seconds
  24. 造轮子系列之RPC 1:如何从零开始开发RPC框架
  25. RPC 1: how to develop RPC framework from scratch
  26. 造轮子系列之RPC 1:如何从零开始开发RPC框架
  27. RPC 1: how to develop RPC framework from scratch
  28. 一次性捋清楚吧,对乱糟糟的,Spring事务扩展机制
  29. 一文彻底弄懂如何选择抽象类还是接口,连续四年百度Java岗必问面试题
  30. Redis常用命令
  31. 一双拖鞋引发的血案,狂神说Java系列笔记
  32. 一、mysql基础安装
  33. 一位程序员的独白:尽管我一生坎坷,Java框架面试基础
  34. Clear it all at once. For the messy, spring transaction extension mechanism
  35. A thorough understanding of how to choose abstract classes or interfaces, baidu Java post must ask interview questions for four consecutive years
  36. Redis common commands
  37. A pair of slippers triggered the murder, crazy God said java series notes
  38. 1、 MySQL basic installation
  39. Monologue of a programmer: despite my ups and downs in my life, Java framework is the foundation of interview
  40. 【大厂面试】三面三问Spring循环依赖,请一定要把这篇看完(建议收藏)
  41. 一线互联网企业中,springboot入门项目
  42. 一篇文带你入门SSM框架Spring开发,帮你快速拿Offer
  43. 【面试资料】Java全集、微服务、大数据、数据结构与算法、机器学习知识最全总结,283页pdf
  44. 【leetcode刷题】24.数组中重复的数字——Java版
  45. 【leetcode刷题】23.对称二叉树——Java版
  46. 【leetcode刷题】22.二叉树的中序遍历——Java版
  47. 【leetcode刷题】21.三数之和——Java版
  48. 【leetcode刷题】20.最长回文子串——Java版
  49. 【leetcode刷题】19.回文链表——Java版
  50. 【leetcode刷题】18.反转链表——Java版
  51. 【leetcode刷题】17.相交链表——Java&python版
  52. 【leetcode刷题】16.环形链表——Java版
  53. 【leetcode刷题】15.汉明距离——Java版
  54. 【leetcode刷题】14.找到所有数组中消失的数字——Java版
  55. 【leetcode刷题】13.比特位计数——Java版
  56. oracle控制用户权限命令
  57. 三年Java开发,继阿里,鲁班二期Java架构师
  58. Oracle必须要启动的服务
  59. 万字长文!深入剖析HashMap,Java基础笔试题大全带答案
  60. 一问Kafka就心慌?我却凭着这份,图灵学院vip课程百度云