Java注解

Java 注解用于为 Java 代码提供元数据。作为元数据,注解不直接影响你的代码执行,但也有一些类型的注解实际上可以用于这一目的。Java 注解是从 Java5 开始添加到 Java 的。
1- 什么是注解?
1.1- 编译指令
1.2- 编译时指令
1.3- 运行时指令
2- 内置注解
2.1- @Deprecated
2.2- @Override
2.3- @SuppressWarnings
3- 编写注解
3.1- 你的第一个注解
3.2- 注解与元素值
3.3- @Retention & @Target
3.4- Annotation & Reflection
4- 注解处理工具 (高级知识)

1- 什么是注解

Java 注解用于为 Java 代码提供元数据。作为元数据,注解不直接影响你的代码执行,但也有一些类型的注解实际上可以用于这一目的。Java 注解是从 Java5 开始添加到 Java 的。

Java 注解通常用于以下目的:
  1. 编译器指令
    		</li>
    
  2. 编译时指令
    		</li>
    
  3. 运行时指令
    		</li>
    

1.1- 编译指令

Java 有 3 个内置的注解,你可以用它来发出指令到 Java 编译器。
  • @Deprecated
  • @Override
  • @SuppressWarnings
这些注释后面详细文件中会解释。

1.2- 编译时指令

当你创建建软件项目时,Java 注释可以在编译时使用。构建过程包括生成的源代码,编译源文件,生成 XML 文件 (例如部署描述符),包装编译代码和文件到一个 JAR 文件等。构建软件通常是通过像 Apache Ant 组织的 Apache Maven 的自动构建工具完成。 构建工具可以扫描你的 Java 代码指定的注解并生成源代码或基于这些注解其他文件。

1.3- 运行时指令

通常情况下,Java 注解中不存在于编译后的 Java 代码。这是可能的,但是,定义自己的注解是在运行时可用。这些注解然后可以通过 Java 反射访问,并用于发出指令到您的程序,或者一些第三方 API。

2- 内置注解

Java 有 3 个重要注解可用:
  • @Deprecated
  • @Override
  • @SuppressWarnings
	</div>

2.1- @Deprecated

这是用来注解过时的东西,如类或方法的注解; 最好我们不应该再使用它。
如果你使用的东西过时,编译器会通知您应该使用的另一种方式。

或 IDE 编程像 Eclipse,它也给你显示出可视化通知。
  • DeprecatedMethodDemo.java
	</div>
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
	</div>
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 {

// This method is overridden method getName() of the superclass.
// @Override not required to write on this method.
// But it is necessary if someone changed the name of the method getName()
// in parent class, an error message will tell you.
@Override
public String getName() {
    return "Java Coding";
}

}

这里是 Java 编译器警告:

2.3- @SuppressWarnings

@SuppressWarnings 注解使编译器抑制对某个方法的警告。例如,如果一个方法调用的方法已过时,或使一个不安全的类型转换,编译器可能会产生一个警告。您可以通过包含使用 @SuppressWarnings 注解代码的方法标注抑制这些警告。

下面我们来看看一个例子:
  • SuppressWarningsDemo.java
	</div>
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
	</div>
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&lt;String&gt; datas= (List&lt;String&gt;) this.getDatas();        

}

}

来自编译器的警告:

3- 编写你自己的注解

@interface 是声明一个注释的关键字,而这个注解非常相似于接口。注解可有或没有元素。注释元素的特点:

  • 没有函数体
    		</li>
    
  • 没有函数参数
    		</li>
    
  • 返回的声明必须在一个特定的类型:
    • 基本类型 (boolean, int, float,...)
    • 枚举
      				</li>
      
    • 注解
      				</li>
      
    • 类 (如:String.class)
      				</li>
      
    		</li>
    
  • 元素可以有默认值
    		</li>
    

3.1- 你的第一个注解

  • MyFirstAnnotation.java
	</div>
package com.yiibai.tutorial.ann1;

public @interface MyFirstAnnotation {

// element name.
public String name();

// Element description, default value "".
public String description() default "";  

}

注释可以用在:
  1. TYPE - 类,接口 (包括注释类型) 或枚举声明
  2. FIELD - 字段声明 (包括枚举常量)
  3. METHOD - 方法声明
  4. PARAMETER - 参数声明
  5. CONSTRUCTOR - 构造函数声明
  6. LOCAL_VARIABLE - 局部变量声明
  7. ANNOTATION_TYPE - 注解声明
  8. PACKAGE - 包声明
  • UsingMyFirstAnnotation.java
package com.yiibai.tutorial.ann1;

@MyFirstAnnotation(name = "Some name", description = "Some description")
public class UsingMyFirstAnnotation {

// Annotation on Constructor.
// The value of the element name is "John"
// Value element description is "Write by John".
@MyFirstAnnotation(name = "John", description = "Write by John")
public UsingMyFirstAnnotation() {

}

// Annotation tied up method.
// The value of the element name is "Tom"
// Description element is not declared, it will be assigned a default value    
@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 {

// Element named 'value'
// There is a bit special when using this element.    
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() {

}

// Initialize the elements of Annotation in the usual way.
// Element 'name' using default.
@AnnWithValue(value = 100)
public void someMethod2() {

}


// With element 'value', you can just write out the value of it.    
@AnnWithValue(100)
public void someMethod3() {

}

}

3.3- @Retention & @Target

@Retention & @Target 是 Java 的两个可用的注解。
@Retention: 使用时要注意一些注解的存在层次。
特别是,有 3 个级别的所提到东西存在要注意:
  1. RetentionPolicy.SOURCE: 存在于源代码,并编译器自由识别。
  2. RetentionPolicy.CLASS: 它的存在是由编译器识别,但不是由虚拟机在运行时。
  3. RetentionPolicyRUNTIME: 达到存在的最高级别,由编译器和由虚拟机在运行时确定的。
@Target: 在使用时要注意另一个注解及其使用范围。
  1. ElementType.TYPE - 附在类,接口,枚举,注解的声明。
  2. ElementType.FIELD - 附在字段的声明和枚举常量。
  3. ElementType.METHOD - 附在方法的声明。
  4. ElementType.PARAMETER - 附在参数的声明
  5. ElementType.CONSTRUCTOR - 附在构造函数的声明
  6. ElementType.LOCAL_VARIABLE - 附在局部变量
  7. ElementType.ANNOTATION_TYPE - 附在注释的声明
  8. ElementType.PACKAGE - 附在包的声明
  • AnnFM.java
	</div>
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
	</div>
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&lt;?&gt; 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("&lt;H3&gt;" + clazz.getName() + "&lt;/H3&gt;");
        sb.append("\n");


        // Get the value of the element 'border'.
        String border = annUL.border();

        sb.append("&lt;UL style='border:" + border + "'&gt;");
        
        // 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("&lt;LI style='margin:5px;padding:5px;background:"
                        + background + ";color:" + color + "'&gt;");
                sb.append("\n");
                sb.append(method.getName());
                sb.append("\n");
                sb.append("&lt;/LI&gt;");
                sb.append("\n");
            }
        }
        sb.append("&lt;/UL&gt;");
    }
    writeToFile(clazz.getSimpleName() + ".html", sb);
}

// Write to Console (Or file)
private static void writeToFile(String fileName, StringBuilder sb) {
    System.out.println(sb);
}

}

运行示例的结果:

写入 HTML 文件:

4- 注解处理工具 (高级知识)

这种情况是:

您可以创建自己的注解,并在 Java 应用程序中使用它们。您将使用这些注解规则。要 Java 编译器来通知应用错误的规则,在编译时的错误。

如果使用 Eclipse 编写代码,Eclipse 将通知用户错误的一些正确用法。
</div>