thinking-in-java(20)注解

【1】注解介绍

1)注解是什么?

注解(元数据)是 java提供的一种对程序元素(如类,方法,变量)打标记的方法;以便运行程序或编译器可以识别这些元素进行特殊处理;最典型的用法是,框架代码启动时扫描某注解修饰的所有类并将其加载到内存,以构建系统底层框架更直白点,类,方法,变量被注解修饰后,更容易被识别以便加载

补充: 显然,开发或学习底层框架的同学肯定必不可少要学习注解;所以注解是相当重要的;


【2】java内置的三种注解 

1)@Override: 表示被标记的方法将覆盖超类中的方法;

2)@Deprecated:表示被标记的元素(类或方法)被废弃了 ; 如果代码使用该元素,则编译器会发出警告;

3)@SuppressWarnings关闭不当的编译器警告信息;


【3】4种标准元注解

1)元注解:元注解的作用是负责修饰其他注解(参与其他注解的定义或声明)。 java5.0 定义了4个标准的元注解类型; (干货——你也可以认为被注解修饰,就是被注解打标记

1.1)@Target元注解,用于指定被修饰注解可以应用到哪些元素上

如 注解可以被应用到 packages,type(类,接口,枚举,Annotation类),类型成员(方法,构造方法,成员变量,枚举值),方法参数和本地变量等;

注解定义例子1:

@Target(ElementType.METHOD) // 表示用于修饰(标记)方法
@Retention(RetentionPolicy.RUNTIME) // 表示运行时可用 
public @interface Test {} ///:~

注解应用例子1: 

public class Testable {public void execute() {System.out.println("Executing..");}@Test  // Test 注解用于修饰方法void testExecute() {execute();}
}

1.2)@Retention元注解,用于指定被修饰注解的生命周期

  • SOURCE:源文件有效;被编译器丢弃
  • CLASS:class文件有效;被JVM丢弃
  • RUNTIME :运行时有效(常用);VM将在运行期也保留注解,通过反射机制读取注解;

1.3)@Document  用于指定被修饰的注解可以被 javadoc 工具文档化;

1.4)@Inherited   用于指定被修饰的注解是可以被继承的

2)上面例子中修饰的注解 Test,是没有任何成员方法的。下面我们来看有成员方法的注解UseCase;·

// 下面定义了一个注解UseCase:该注解作用于方法,该注解在运行时发挥作用
// 该注解UseCase应用于什么地方
@Target(ElementType.METHOD)
// 该注解UseCase的应用级别,源代码-SOURCE, 类文件中-CLASS, 运行时-RUNTIME
@Retention(RetentionPolicy.RUNTIME)
public @interface UseCase {public int id();public String description() default "no description"; // no description 是默认值
}
/*
D:\workbench_idea\study4vw\thinkinjava\src>javap chapter20.UseCase
Compiled from "UseCase.java"
public interface chapter20.UseCase extends java.lang.annotation.Annotation {public abstract int id();public abstract java.lang.String description();
}
*/

反编译(javap)后的源码:可以看到,注解就是一个接口,该接口的父类是 Annotation 注解接口类型,当然了,接口中的方法都是抽象方法。

2.1)使用 UseCase注解;

// 荔枝-有3个方法被注解UseCase修饰为用例
public class PasswordUtils {// 将 UseCase 注解作用于方法@UseCase(id = 47, description = "validatePassword method")public boolean validatePassword(String password) {return (password.matches("\\w*\\d\\w*"));}@UseCase(id = 48) // description 默认为 no descriptionpublic String encryptPassword(String password) {return new StringBuilder(password).reverse().toString();}@UseCase(id = 49, description = "checkForNewPassword method")public boolean checkForNewPassword(List<String> prevPasswords, String password) {return !prevPasswords.contains(password);}
}
/* 反编译简要结果如下:
D:\workbench_idea\study4vw\thinkinjava\src>javap chapter20.PasswordUtils
Compiled from "PasswordUtils.java"
public class chapter20.PasswordUtils {public chapter20.PasswordUtils();public boolean validatePassword(java.lang.String);public java.lang.String encryptPassword(java.lang.String);public boolean checkForNewPassword(java.util.List<java.lang.String>, java.lang.String);
}
*/

解析注解

/*** 注解解析测试用例*/
public class AnnotationDiyTest {public final static <T> void  f1(Class<T> c1) {for (Method method : c1.getMethods()) { // 获取类定义方法UseCase useCase = method.getAnnotation(UseCase.class); // 获取方法上某个注解if (useCase != null) {System.out.println(useCase.id() + "-" + useCase.description()); // 解析注解}}}public static void main(String[] args) {f1(PasswordUtils.class);}
}
/*
47-validatePassword method
48-no description
49-checkForNewPassword method
*/

【4】自定义注解

UseCase注解有两个方法,方法返回类型有 int,String;此外还有其他返回类型,包括

所有基本类型;
String;
Class
enum;
Annotation;// 注解的成员方法的返回值类型还可以是注解类型
以及以上类型的数组; 

下面定义一个嵌套注解(即注解的方法返回类型是注解类型)

@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface SQLString {int value() default 0;String name() default "";Constraints constraints() default @Constraints();// 嵌套注解
} // /:~
// 定义注解(并定义嵌套注解)
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface SQLInteger {int value() default 0;String name() default "";// 嵌套注解,因为 Constraints 也是注解类型Constraints constraints() default @Constraints; 
} // /:~
// 荔枝-定义注解(并定义嵌套注解)
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface SQLDouble {double value() default 0f;// 嵌套注解,因为 Constraints 也是注解类型Constraints constraints() default @Constraints;
}
// 荔枝-定义注解用于生成一个数据库表
@Target(ElementType.TYPE) // 注解作用于哪里(注解的作用对象)
// Applies to classes only
@Retention(RetentionPolicy.RUNTIME) // 注解的作用时间(这里是运行时) 
public @interface DBTable {// DBTable 有一个name元素// 这个注解通过使用 value元素 为处理器创建数据库表提供的表名public String value() default "";
} // /:~
// 荔枝-为修饰 javabean域 准备的注解
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Constraints {boolean primaryKey() default false; // 主键boolean allowNull() default true; // 允许为空boolean unique() default false; // 唯一键
} // /:~

使用注解创建数据库表对应的javabean

// DBTable 注解作用于类
@DBTable("MEMBER")
public class Member {@SQLString(30) String firstName;@SQLString(value=50, name = "lastName") String lastName;@SQLInteger(name = "age", constraints = @Constraints(primaryKey=true, allowNull=false, unique=true)) Integer age;@SQLString(value = 30 , name = "handle", constraints = @Constraints(primaryKey = true))String handle;static int memberCount;public String getHandle() {return handle;}public String getFirstName() {return firstName;}public String getLastName() {return lastName;}public String toString() {return handle;}public Integer getAge() {return age;}
} // /:~

使用注解的快捷方式:如果注解中定义了名为value元素(value方法),且在使用注解时,该元素是唯一一个需要复制的元素,那么只需要给出value元素的值即可,无需写键值对形式
@DBTable("MEMBER")-快捷方式 , @DBTable(value="MEMBER")-普通方式


【5】使用apt处理注解

1)问题, 上述代码中,都需要为注解编写处理器以解析注解; 很麻烦;

使用 apt类库方法可以生成注解处理器,apt 是使用源代码生成注解的,无法通过class文件获取类的属性;但 mirror api 可以允许程序员在源代码中查看类属性,如方法,属性;

2)注解

// 抽取注解
@Target(ElementType.TYPE) //
@Retention(RetentionPolicy.SOURCE) // 在源文件起作用 
public @interface ExtractInterface {public String value();
} // /:~

【6】小结

java se5仅提供了很少的注解,大多数情况下,需要自定义注解及注解处理器(特别是开发底层框架的时候,需要自定义注解);

javassist 能够用来操作字节码;mirror api 能够用来找出java源代码中的元素 (apt-mirror-api maven repo);

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/330765.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Servlet---注解开发

1.引入 在Servlet3.0以后的版本提供了Servlet注解配置&#xff0c;大大简化了代码编写。它可以替代xml文件的配置 2.代码实现 <1>注解开发代码如下&#xff1a; WebServlet(value "/servlet1", initParams {WebInitParam(name "charset", val…

Git操作常用的命令都在这里了

转载自 Git操作常用的命令都在这里了 创建仓库 git init 在当前目录执行&#xff0c;会生成 .git目录文件&#xff0c;这个和SVN一致。 提交到仓库 git commit -m "first commit" -m&#xff1a;表示提交描述&#xff0c;必须要填。 添加到远端仓库 git remote …

DevExperience(1801)

【1】 关于路径和文件名命名规范&#xff1a;1&#xff09;window 操作系统 的路径名和文件名是不区分大小写的&#xff0c;Linux等其他操作系统都区分大小写的&#xff1b;2&#xff09;某些部署在 Linux系统的项目&#xff0c;其路径名和文件名建议均用小写&#xff1b;不然一…

web项目的创建和发布

1.Web项目的目录结构 2.Web项目的创建 <1>首先创建一个空的java项目 <2>选择模块,创建一个新模块 <3>选择javaq企业开发块,先勾选javaEE版本再勾选下方的Web Application才会出现对应的版本 <4>一路next之后给模块取名点击finish,再点击Apply后ok则…

telnet实现本地回显

下面以访问 localhost:8080 站点为荔枝说明如何设置 telnet的回显&#xff1b;1&#xff09;操作系统命令行输入 telnet localhost 8080 回车&#xff1b;2&#xff09;同时键入 ctrl 和 ] 键&#xff0c;进入 telnet 命令行&#xff1b;3&#xff09;记不住 telnet 命令的童鞋…

DevOps到底是什么鬼?DevOps介绍及工具推荐

转载自 DevOps到底是什么鬼&#xff1f;DevOps介绍及工具推荐 什么是DevOps DevOps是Development和Operations的组合&#xff0c;是一组过程、方法与系统的统称&#xff0c;用于促进开发&#xff08;应用程序/软件工程&#xff09;、技术运营和质量保障&#xff08;QA&#xf…

请求对象Request

1.概念 <1>请求&#xff1a;请求:获取资源。在BS架构中&#xff0c;就是客户端浏览器向服务器端发出询问。 <2>请求对象&#xff1a;就是在项目当中用于发送请求的对象。 <3>对象创建&#xff1a;需要实现ServletRequest和HttpservletRequest接口&#xff0…

Oracle-26-内连接(等值、不等值连接、自然连接)外连接(左外、右外、全连接)using子句

转自&#xff1a; http://blog.csdn.net/wy_0928/article/details/51155498 【总结】连接分类 【0】什么是数据库连接&#xff1f; 1&#xff09;当一次查询涉及到两个表时&#xff1a;就要使用连接查询了&#xff0c;其中join如果不带有其他标识&#xff0c;则默认是内连接 …

百度分布式配置管理平台-Disconf

转载自 【推荐】百度分布式配置管理平台-DisconfDisconf介绍 全称&#xff1a;Distributed Configuration Management Platform&#xff0c;即分布式配置管理平台。 Disconf专注于各种分布式系统配置管理的通用组件和通用平台, 提供统一的配置管理服务。主要目标&#xff1a; 部…

运算符优先级的问题

注意&#xff1a;逻辑非>逻辑与>逻辑或

数据库表连接总结:等值连接, 自然连接,左外连接,右外连接,内连接,全外连接;

【1】等值连接1&#xff09;连接&#xff1a;凡是查询涉及到两个以上的表&#xff0c;就需要将表连接&#xff1b;2&#xff09;就是用where子句做的连接查询&#xff1b;连接查询的列名可以不同&#xff1b;【2】自然连接&#xff1a;select * from a_tbl natual join b_tbl这…

网站性能测试指标(QPS,TPS,吞吐量,响应时间)详解

转载自 网站性能测试指标&#xff08;QPS&#xff0c;TPS&#xff0c;吞吐量&#xff0c;响应时间&#xff09;详解常用的网站性能测试指标有&#xff1a;吞吐量、并发数、响应时间、性能计数器等。 并发数 并发数是指系统同时能处理的请求数量&#xff0c;这个也是反应了系统的…

Request获取参数封装方式

浏览器请求界面 1.获取参数手动封装数据 WebServlet("/ServletDemo4") public class ServletDemo4 extends HttpServlet {Overrideprotected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {//根据参数名获取…

Access restriction: The type 'BASE64Encoder' is not API 的解决方法

转自&#xff1a; https://www.mkyong.com/java/access-restriction-the-type-base64encoder-is-not-accessible-due-to-restriction/ If you insist want to use sun.misc.BASE64Encoder, in Eclipse, right click on the project, properties -> Java compiler –> Err…

Mycat - 数据库分库分表中间件,国内最活跃的、性能最好的开源数据库中间件

转载自 Mycat - 数据库分库分表中间件&#xff0c;国内最活跃的、性能最好的开源数据库中间件Mycat是什么 Mycat - 数据库分库分表中间件&#xff0c;国内最活跃的、性能最好的开源数据库中间件&#xff01; 一个彻底开源的&#xff0c;面向企业应用开发的大数据库集群支持事务…

响应对象Response

1.概念【响应给浏览器】 响应∶回馈结果。在B/S架构中&#xff0c;就是服务器给客户端浏览器反馈结果。响应对象∶就是在项目中用于发送响应的对象。实现接口&#xff1a;ServletResponse和HttpServletResponse【浏览器访问服务器后&#xff0c;服务器给客户端响应的数据会封装…

调用toString()方法的注意事项

【1】荔枝&#xff1a;Object转为 String&#xff1b; response.setContentType("text/html;charsetUTF-8"); PrintWriter out response.getWriter();request.setCharacterEncoding("UTF-8"); HttpSession session request.getSession(); //设置session超…

Java内存泄漏介绍

转载自 Java内存泄漏介绍内存管理是Java最重要的优势之一&#xff0c;你只需创建对象&#xff0c;Java垃圾收集器会自动负责分配和释放内存。但是&#xff0c;情况并不那么简单&#xff0c;因为在Java应用程序中经常发生内存泄漏。本章会说明什么是内存泄漏&#xff0c;为什么发…

Servlet请求和响应总结

1.解决乱码问题 通过Request的设置编码表方法和Respose设置浏览器展示编码表解决 //设置请求字符编码,防止乱码 req.setCharacterEncoding("utf-8"); //设置浏览器响应编码[html类型的文本,字符集为utf-8] resp.setContentType("text/html;charsetutf-8"…

java虚拟机采用UTF-16编码格式对字符进行编码

转自&#xff1a; https://www.ibm.com/developerworks/cn/java/j-lo-chinesecoding/ 【UTF-16】 说到 UTF 必须要提到 Unicode&#xff08;Universal Code 统一码&#xff09;&#xff0c;ISO 试图想创建一个全新的超语言字典&#xff0c;世界上所有的语言都可以通过这本字典来…