Java注解全面解析:定义、原理、应用及最新内容全知道

点击上方“Java专栏”,选择“置顶或者星标”

Java注解全面解析:定义、原理、应用及最新内容全知道

第一时间阅读精彩文章!

自Java5.0版本将注解引入后,注解就成了Java平台极为重要的一部分。在开发过程中,我们常在应用代码里看到像@Override、@Deprecated这类注解。在这篇文章里,我会向大家说明究竟什么是注解,为何要引入注解,注解是怎样工作的,怎样编写自定义注解(借助例子),在什么情形下能够使用注解,以及最新注解和ADF(应用开发框架)。这需要花费一些时间,因此给自己准备一杯咖啡,让我们一同进入注解的世界吧。

什么是注解?

用一个词能够描述注解,这个词是元数据,元数据是一种描述数据的数据。所以,能够说注解是源代码的元数据。比如,有下面这段代码:

@Override
public String toString() {
return 这是当前对象的字符串表示形式。;
}

在上面的代码里,我对toString()方法进行了重新编写,并且使用了@Override注解。

但是,即便我不运用@Override注解来标记代码,程序依旧能够正常运行。那么,这个注解究竟意味着什么呢?如此书写又有什么益处呢?

事实上,@Override告知编译器,这个方法是一个重写方法,也就是描述方法的元数据。要是父类中不存在该方法,编译器就会报错,提示该方法没有重写父类中的方法。如果我不小心出现拼写错误,比如把toString()写成了toStrring(){double r},并且我没有使用@Override注解,那么程序仍然能够编译运行,不过运行结果会与我期望的相差很大,现在我们知晓了什么是注解,而且使用注解对阅读程序有帮助。

Annotation是一种特殊修饰符,它应用于类、方法、参数、变量、构造器及包声明中,它是一种工具,由JSR - 175标准选择用来描述元数据。

为什么要引入注解?

在使用Annotation之前,甚至在使用之后,XML都被广泛应用于描述元数据。不知从何时起,一些应用开发人员和架构师发现XML的维护状况越来越差。他们希望使用与代码紧密耦合的东西,而非像XML那样与代码是松耦合的,在某些情况下甚至是完全分离的代码描述。在Google中搜索“XML vs. annotations”,你会看到许多关于这个问题的辩论,最有趣的是,XML配置是为分离代码和配置而引入的,上述两种观点可能会让你很疑惑,两者观点似乎构成一种循环,且各有利弊,下面我们通过一个例子来理解这两者的区别。

假如你想为应用设置很多常量或参数,在这种情况下,XML是个很好的选择,因为它不会与特定代码相连。如果你想将某个方法声明为服务,那么使用Annotation会更好,因为这种情况下需要注解与方法紧密耦合,开发人员也必须认识到这一点。

另一个很重要的因素是,Annotation定义了一种描述元数据的标准方式。在此之前,开发人员通常采用他们自己的方式来定义元数据。比如,使用标记interfaces,注释,transient关键字等。每个程序员都按自己的方式定义元数据,并非像Annotation这种标准方式。

当前,有不少框架把XML与Annotation这两种方式结合起来运用,以此平衡两者之间的优势与劣势。

Annotation是怎样工作的,如何编写自定义的Annotation?

在讲述这部分内容之前,建议你先去下载Annotation的示例代码AnnotationsSample.zip 。将其下载后,放置在你习惯使用的IDE里,这些代码能够助力你更深入地理解Annotation机制。

编写Annotation十分简便,能够把Annotation的定义和接口的定义作比较。我们来看两个例子,一个是标准的注解@Override,另一个是用户自定义注解@Todo。

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.SOURCE)
public @interface Override {
}

对于@Override注释你或许有一些疑问,它没做任何事,那它怎样检查父类中有同名函数呢。当然,别惊讶,我是在逗你。@Override注解的定义不止这点代码。这部分内容很重要,我得再次重复:Annotations只是元数据,与业务逻辑无关。理解起来有点难,但就是如此。如果Annotations不包含业务逻辑,那就得有人来实现这些逻辑,做这件事的是元数据的用户,Annotations仅提供其定义的属性(类/方法/包/域)的信息,Annotations的用户(同样是一些代码)读取这些信息并实现必要的逻辑。

当我们运用Java的标注Annotations(比如@Override)时,JVM作为一个用户在字节码层面开展工作。此时,应用开发人员既无法控制也不能使用自定义的注解。所以,我们来讲解一下怎样编写自定义的Annotations。

我们来逐个讲述编写自定义注解的关键要点。在上面所举的例子当中,你能够看到有一些注解被应用于注解之上。

J2SE5.0版本在java.lang.annotation中,提供了四种元注解,这些元注解专门用于注解其他的注解。

@Documented –注解是否将包含在JavaDoc中

@Retention –什么时候使用该注解

@Target? –注解用于什么地方

@Inherited – 是否允许子类继承该注解

@Documented是一个简单的Annotations标记注解,它用于表示是否要将注解信息添加在java文档中 。

@Retention– 定义该注解的生命周期。

RetentionPolicy.SOURCE会在编译阶段被丢弃,这些注解在编译结束后不再有任何意义,所以不会被写入字节码,@Override和@SuppressWarnings都属于这类注解。

RetentionPolicy.CLASS会在类加载的时候被丢弃,它在字节码文件的处理中是有用的,并且注解默认使用这种方式。

RetentionPolicy.RUNTIME意味着始终不会丢弃,在运行期也会保留该注解,所以能够使用反射机制读取该注解的信息,我们自定义的注解通常采用这种方式。

@Target表示该注解的使用位置。若未明确指出,此注解可置于任何地方。以下是一些可用参数。需说明的是,属性的注解相互兼容。若想给7个属性都添加注解,仅排除一个属性,那么在定义target时需包含所有属性。

ElementType.TYPE,它被用来描述类,它被用来描述接口,它被用来描述enum声明。

ElementType.FIELD:用于描述实例变量

ElementType.METHOD

ElementType.PARAMETER

ElementType.CONSTRUCTOR

ElementType.LOCAL_VARIABLE

ElementType.ANNOTATION_TYPE,这是另外一个注释。

ElementType.PACKAGE,它被用来记录java文件的package信息

@Inherited– 定义该注释和子类的关系

那么,注解的内部究竟是怎样定义的呢?Annotations仅支持基本类型、String以及枚举类型。注释里所有的属性都被定义为方法,并且允许提供默认值。

@Target(ElementType.METHOD)

保留(保留策略为运行时)

@interface Todo {

公共枚举类型Priority,它有三个值,分别是LOW、MEDIUM、HIGH 。

公共枚举类型名为状态,其包含两个值,分别是已启动和未启动 。

声明一个默认值为 "Yash" 的作者方法 ,该方法返回字符串类型 。

优先级 priority(),默认优先级为 Priority.LOW;

Status status ,其默认值为 Status.NOT_STARTED ;

下面的例子演示了如何使用上面的注解。

@Todo优先级为待办事项的中等优先级,作者是"Yashwant"状态为待办事项状态中的已开始状态
public void incompleteMethod1() {

//But it’s not complete yet
}

要是注解里仅有一个属性,那么能够直接将其命名为“value”,在使用的时候不需要再去标明属性名。

@interface Author{

String value();

@Author("Yashwant")

public void someMethod() {

但到目前为止一切看上去都还挺好。我们定义了自身的注解,并且把它应用到业务逻辑的方法上。如今我们要写一个用户程序来调用我们的注解。在此处我们得使用反射机制。要是你熟悉反射代码,就会晓得反射能够提供类名、方法以及实例变量对象。所有这些对象都有getAnnotation()这个方法,用以返回注解信息。我们要将这个对象进行转换,转换为我们自定义的注释,这一操作需在使用instanceOf()检查之后进行,与此同时,还能够调用自定义注释里面的方法。查看以下的实例代码,其使用了上面的注解:

将变量 businessLogicClass 赋值为 BusinessLogic 类的 class 对象 。
for获取业务逻辑类的方法,将其赋值给变量method ,括号内的内容为获取方法的具体操作 。
获取方法的Todo类注解,将其强制转换为Todo类型并赋值给Todo todoAnnotation
if(todoAnnotation != null) {
System.out.println(" Method Name : " + method.getName());
System.out.println(" Author : " + todoAnnotation.author());
System.out.println(" Priority : " + todoAnnotation.priority());
System.out.println(" Status : " + todoAnnotation.status());
}
}

注解用例

注解功能十分强大,Spring和Hebernate等框架在日志及有效性方面大量运用了注解功能,注解能够应用于使用标记接口的地方,不同之处在于标记接口用于定义完整的类,而你能够为单个方法定义注释,比如是否将一个方法暴露为服务 。

最新的servlet3.0引入了许多新注解,这些注解中,和servlet安全相关的注解尤其值得关注。

HandlesTypes注解,用于表示一组应用类,这些应用类会被传递给ServletContainerInitializer 。

HttpConstraint注解代表安全约束,此安全约束应用于所有HTTP方法的请求,它与ServletSecurity注释中定义的HttpMethodConstraint安全约束不一样。

HttpMethodConstraint指明了不同类型请求的安全约束,它和ServletSecurity注解中描述HTTP协议方法类型的注释不一样。

MultipartConfig这个注解,标注在Servlet上面,它表示,该Servlet希望处理的请求的MIME类型是multipart/form-data。

ServletSecurity这个注解,标注在Servlet继承类之上,它会强制HTTP协议请求,遵循安全约束。

WebFilter注解,它用于声明一个Server过滤器 。

WebInitParam注解用于声明Servlet或过滤器中的初始化参数,它通常与@WebServlet或者@WebFilter配合使用。

WebListener注解,用于为Web应用程序上下文,声明不同类型事件的监听器。

WebServlet这个注解,用于声明一个Servlet的配置。

ADF (应用程序框架)和注解

现在我们开始讨论文章的最后一部分了 应用程序框架被称为ADF 它由Oracle开发 用于创建Oracle融合应用 我们已经了解了注解的优缺点 也知道如何编写自定义的注解 但我们应该将注解应用在ADF的哪部分呢 ADF是否提供了一些朴素的注解 这是个很好的问题 确实在ADF中大量使用注解存在一些限制之前提到的应用框架比如Spring和Hibernate运用AOP(面向侧面的程序设计),在AOP里框架提供一种机制,能在事件的预处理以及后续处理中注入代码,比如有一个钩子可在方法执行之前和之后添加代码,这样就能在这些地方编写用户代码,而ADF不使用AOP。要是我们拥有任何能够用于注解的用例,那我们或许需要借助继承的途径来达成。


以上,就是今天的分享,期望大家会喜欢,感觉内容挺好的,欢迎点击「在看」

支持,谢谢各位。



喜欢文章,点个在看 

你可能想看:
« 上一篇
下一篇 »

相关推荐

java中什么是冒泡,冒泡算法

2026年09月06日

30阅读

java中冒号,java双冒号

2026年09月06日

28阅读

java中的->,java中的是什么意思

2026年09月06日

28阅读

java中的super用法,Java中super的说明

2026年09月06日

29阅读

java中反射的应用,java中反射的应用场景

2026年09月06日

27阅读

java中开关的定义,Java关键字有哪些

2026年09月06日

29阅读