Java注解用于为Java代码提供元数据。作为元数据,注解不直接影响你的代码执行,但也有一些类型的注解可以用于这一目的。Java注解是从Java5开始添加到Java中。
1. 什么是注解
Java注解用于为Java代码提供元数据。作为元数据,注解不直接影响你的代码执行,但也有一些类型的注解实际上可以用于这一目的。
Java注解通常用于以下目的:
- 编译器指令
- 编译时指令
- 运行时指令
1.1. 编译指令
Java有3
个内置的注解,你可以用它来发出指令到Java编译器。
这些注释后面详细文件中会解释。
1.2. 编译时指令
当创建建软件项目时,Java注释可以在编译时使用。构建过程包括生成的源代码,编译源文件,生成XML文件(例如部署描述符),包装编译代码和文件到一个JAR文件等。构建软件通常是通过像Apache Ant组织的Apache Maven的自动构建工具完成。构建工具可以扫描你的Java代码指定的注解并生成源代码或基于这些注解其他文件。
1.3. 运行时指令
通常情况下,Java注解中不存在于编译后的Java代码。这是可能的,但是,定义自己的注解是在运行时可用。这些注解然后可以通过Java反射访问,并用于发出指令到程序,或者一些第三方API。
2. 内置注解
Java有3个重要注解可用:
2.1. @Deprecated注解
它是用来注解过时的东西,如类或方法的注解; 如果使用的东西过时,编译器会通知应该使用的另一种方式。或IDE工具,像Eclipse,它也给显示出可视化通知。
文件:DeprecatedMethodDemo.java
package com.yiibai.tutorial.ann.builtin;
import java.util.Date;
public class DeprecatedMethodDemo {
/**
* @deprecated replaced by {@link #todo(String,Date)}
*/
@Deprecated
public void todoJob(String jobName) {
System.out.println("Todo " + jobName);
}
public void todo(String jobName, Date atTime) {
System.out.println("Todo " + jobName + " at " + atTime);
}
public void todoNothing() {
System.out.println("Todo Nothing");
}
public static void main(String[] args) {
DeprecatedMethodDemo obj = new DeprecatedMethodDemo();
obj.todoJob("Java coding");
obj.todoNothing();
}
}
如下图所示,Eclipse将通知:
2.2. @Override注解
@Override
注解来覆盖超类方法在方法使用。如果这个方法不超匹配的方法,编译器就会提示一个错误。
要覆盖超类的方法而使用 @Override
注解不是必需的。如坚持使用它,也是个好主意。万一有人改变超类中的重写方法名称,子类的方法将不再覆盖它。没有@Override
注释,可能不太好找到问题。使用@Override
注解,编译器会提示,在子类中的方法没有完全重写超类的方法。
下面我们来看一个例子:
文件:Job.java
package com.yiibai.tutorial.ann.builtin;
public class Job {
// This is method of Job class.
public String getName() {
return null;
}
}
文件:JavaCoding.java
ckage com.yiibai.tutorial.ann.builtin;
public class JavaCoding extends Job {
// @Override not required to write on this method.
@Override
public String getName() {
return "Java Coding";
}
}
这里是Java编译器警告:
2.3. @SuppressWarnings注解
@SuppressWarnings
注解使编译器抑制对某个方法的警告。例如,如果一个方法调用的方法已过时,或使一个不安全的类型转换,编译器可能会产生一个警告。可以通过包含使用@SuppressWarnings
注解代码的方法标注抑制这些警告。
下面我们来看看一个例子:
文件:SuppressWarningsDemo.java -
package com.yiibai.tutorial.ann.builtin;
import java.util.Date;
public class SuppressWarningsDemo {
@SuppressWarnings("deprecation")
public Date getSomeDate() {
Date date = new Date(2014, 9, 25);
return date;
}
}//
编译器警告如下所示:
文件:SuppressWarningsDemo2.java
package com.yiibai.tutorial.ann.builtin;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
public class SuppressWarningsDemo2 {
public List<?> getDatas() {
List<String> list = new ArrayList<String>();
list.add("One");
return list;
}
@SuppressWarnings({ "deprecation", "unused", "unchecked" })
public void processDatas() {
// You use deprecated Constructor
// Variable 'date' was created, but not used
Date date = new Date(2014, 9, 25);
// Cast unsafe.
// Variable 'datas' is created, but not used in the code.
List<String> datas= (List<String>) this.getDatas();
}
}原文出自【易百教程】,商业转载请联系作者获得授权,非商业请保留原文链接:https://www.yiibai.com/article/detail/8350
编译器警告如下所示:
3. 编写注解
@interface
是声明一个注释的关键字,而这个注解非常相似于接口。注解可有或没有元素。注释元素的特点:
- 没有函数体;
- 没有函数参数;
- 返回的声明必须在一个特定的类型:
- 基本类型 (boolean, int, float,…)
- 枚举
- 注解
- 类(如:String.class)
- 元素可以有默认值;
3.1. 第一个注解
文件:MyFirstAnnotation.java -
package com.yiibai.tutorial.ann1;
public @interface MyFirstAnnotation {
// element name.
public String name();
// Element description, default value "".
public String description() default "";
}
注释可以用在:
TYPE
- 类,接口(包括注释类型)或枚举声明FIELD
- 字段声明(包括枚举常量)METHOD
- 方法声明PARAMETER
- 参数声明CONSTRUCTOR
- 构造函数声明LOCAL_VARIABLE
- 局部变量声明ANNOTATION_TYPE
- 注解类型声明PACKAGE
- 包声明
文件:UsingMyFirstAnnotation.java -
package com.yiibai.tutorial.ann1;
@MyFirstAnnotation(name = "Some name", description = "Some description")
public class UsingMyFirstAnnotation {
// Annotation on Constructor.
@MyFirstAnnotation(name = "John", description = "Write by yiibai.com")
public UsingMyFirstAnnotation() {
}
@MyFirstAnnotation(name = "Tom")
public void someMethod() {
}
// An Annotation on parameter of method.
public void todo(@MyFirstAnnotation(name = "none") String job) {
// An annotation on local variable.
@MyFirstAnnotation(name = "Some name")
int localVariable = 0;
}
}
3.2. 注解与元素值
注解有一个元素命名值,它有一些特点,参考以下示例代码 -
文件:AnnWithValue.java
package com.yiibai.tutorial.ann2;
public @interface AnnWithValue {
public int value();
// Element 'name'.
public String name() default "";
}
文件:UsingAnnWithValue.java
package com.yiibai.tutorial.ann2;
public class UsingAnnWithValue {
@AnnWithValue(name = "Name1", value = 100)
public void someMethod1() {
}
@AnnWithValue(value = 100)
public void someMethod2() {
}
@AnnWithValue(100)
public void someMethod3() {
}
}
3.3. @Retention & @Target
@Retention
& @Target
是Java 的两个可用的注解。@Retention
: 使用时要注意一些注解的存在层次。特别是,有3个级别的所提到东西存在要注意:
RetentionPolicy.SOURCE
: 存在于源代码,并编译器自由识别。RetentionPolicy.CLASS
: 它的存在是由编译器识别,但不是由虚拟机在运行时。RetentionPolicyRUNTIME
: 达到存在的最高级别,由编译器和由虚拟机在运行时确定的。
@Target
: 在使用时要注意另一个注解及其使用范围。
ElementType.TYPE
- 附在类,接口,枚举,注解的声明。ElementType.FIELD
- 附在字段的声明和枚举常量。ElementType.METHOD
- 附在方法的声明。ElementType.PARAMETER
- 附在参数的声明ElementType.CONSTRUCTOR
- 附在构造函数的声明ElementType.LOCAL_VARIABLE
- 附在局部变量ElementType.ANNOTATION_TYPE
- 附在注释的声明ElementType.PACKAGE
- 附在包的声明;
文件:AnnFM.java -
package com.yiibai.tutorial.ann3;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
// Annotation are to be discarded by the compiler.
@Retention(value = RetentionPolicy.SOURCE)
// AnnFM will only be used on FIELD or METHOD.
@Target(value = { ElementType.FIELD, ElementType.METHOD })
public @interface AnnFM {
}
文件:UsingAnnFM.java -
package com.yiibai.tutorial.ann3;
public class UsingAnnFM {
// AnnFM will only be used on FIELD or METHOD.
@AnnFM
protected int someField = 100;
// AnnFM will only be used on FIELD or METHOD.
@AnnFM
public void someMethod() {
}
}
3.4. 注解与反射
Java反射通过一些注解的东西可以识别像类,字段,方法。当然它只能使用@Retention(RetentionPolicy.RUNTIME)
识别注解
下面的例子说明一个程序读取原始的Java文件,并创建HTML文件的注释。每个类相当于一个HTML文件。
文件:AnnHtmlUL.java
package com.yiibai.tutorial.ann4;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Retention(RetentionPolicy.RUNTIME)
// Using for Class, interface, annotation, enum.
@Target(value = { ElementType.TYPE })
// Simulating the <UL> in HTML.
public @interface AnnHtmlUL {
public String border() default "border:1px solid blue;";
}
文件:AnnHtmlLI.java
package com.yiibai.tutorial.ann4;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Retention(RetentionPolicy.RUNTIME)
@Target(value = { ElementType.FIELD,ElementType.METHOD })
// Simulating the <LI> in HTML.
public @interface AnnHtmlLI {
public String background();
public String color() default "red";
}
文件:DocumentClass.java
package com.yiibai.tutorial.ann4;
@AnnHtmlUL(border = "1px solid red")
public class DocumentClass {
private String author;
@AnnHtmlLI(background = "blue", color = "black")
public String getDocumentName() {
return "Java Core";
}
@AnnHtmlLI(background = "yellow")
public String getDocumentVersion() {
return "1.0";
}
@AnnHtmlLI(background = "green")
public void setAuthor(String author) {
this.author = author;
}
@AnnHtmlLI(background = "red", color = "black")
public String getAuthor() {
return author;
}
// This method is not annotated
public float getPrice() {
return 100;
}
}
文件:HtmlGenerator.java
package com.yiibai.tutorial.ann4;
import java.lang.reflect.Method;
public class HtmlGenerator {
public static void main(String[] args) {
Class<?> clazz = DocumentClass.class;
// Check if this class is annotated by Annotation AnnHtmlUL or not.
boolean isHtmlUL = clazz.isAnnotationPresent(AnnHtmlUL.class);
StringBuilder sb = new StringBuilder();
if (isHtmlUL) {
// Get the AnnHtmlUL annotation on this class.
AnnHtmlUL annUL = clazz.getAnnotation(AnnHtmlUL.class);
sb.append("<H3>" + clazz.getName() + "</H3>");
sb.append("\n");
// Get the value of the element 'border'.
String border = annUL.border();
sb.append("<UL + border + "'>");
// Add new line
sb.append("\n");
Method[] methods = clazz.getMethods();
for (Method method : methods) {
// Check if this method is annotated by Annotation AnnHtmlLI or not.
if (method.isAnnotationPresent(AnnHtmlLI.class)) {
// Get the annotation
AnnHtmlLI annLI = method.getAnnotation(AnnHtmlLI.class);
// Get the values of elements.
String background = annLI.background();
String color = annLI.color();
sb.append("<LI
+ background + ";color:" + color + "'>");
sb.append("\n");
sb.append(method.getName());
sb.append("\n");
sb.append("</LI>");
sb.append("\n");
}
}
sb.append("</UL>");
}
writeToFile(clazz.getSimpleName() + ".html", sb);
}
// Write to Console (Or file)
private static void writeToFile(String fileName, StringBuilder sb) {
System.out.println(sb);
}
}
运行示例得到以下结果:
生成的HTML文件: