前言:
注解(Annotation)是Java中的一种特殊符号,用来为代码提供额外的信息。它不会改变程序的逻辑,只是用来给编译器或工具提供指示。例如,
@Override
表示一个方法是重写了父类的方法,@Deprecated
标记一个方法已经不建议使用。本文先讲一些简单的注解,主要带大家了解一下什么是注解,还有它的一些基本使用示例,元注解等等后续更高级的注解会在框架慢慢讲解。
引入
【1】历史:
JDK5.0 新增 --- 注解(Annotation),也叫元数据
【2】什么是注解?
注解其实就是代码里的特殊标记,这些标记可以在编译,类加载,运行时被读取,并执行相应的处理。通过使用注解,程序员可以在不改变原有逻辑的情况下,在源文件中嵌入一些补充信息。代码分析工具、开发工具和部署工具可以通过这些补充信息进行验证或者进行部署。
使用注解时要在其前面增加@符号,并把该注解当成一个修饰符使用。用于修饰它支持的程序元素。
【3】注解的重要性:
Annotation 可以像修饰符一样被使用,可用于修饰包,类,构造器,方法,成员变量,参数,局部变量的声明,这些信息被保存在Annotation的"name=value"对中。在JavaSE中,注解的使用目的比较简单,例如标记过时的功能,忽略警告等。在JavaEE/ArIdroid中注解占据了更重要的角色,例如用来配置应用程序的任何切面,代替JavaEE旧版中所遗留的繁冗代码和XML配置等。未来的开发模式都是基于注解的,JPA(java的持久化API)是基于注解的,Spring2.5以. E都是基于注解的,Hibernate3.x以后也是基于注解的,Struts2有一部分也是基于注解的了,注解是一种趋势,一定程度上可以说 :框架=注解+反射+设计模式。
注解的使用实例
JUnit注解
@Test
@Before
@After
具体详细可以参考之前写的JUnit文章。
文档相关的注解
说明注释允许你在程序中嵌入关于程序的信息。你可以使用 javadoc 工具软件来生成信息,并输出到HTML文件中。
说明注释,使你更加方便的记录你的程序信息。
文档注解我们一般使用在文档注释中,配合javadoc工具
javadoc 工具软件识别以下标签:
其中注意:
Ø @param @return和@exception这三个标记都是只用于方法的。
Ø @param的格式要求: @param 形参名 形参类型 形参说明
Ø @return的格式要求: @return 返回值类型返回值说明,如果方法的返回值类型是void就不能写
Ø @exception的格式要求: @exception 异常类型异常说明
Ø @param和@exception可以并列多个
代码:
/**
* @author : themyth
* @version : 1.0
*/
public class Person {
/**
* 下面是eat方法,实现了xxx功能。
* @param num1 就餐人数
* @param num2 点了几个菜
*/
public void eat(int num1,int num2){
}
/**
*
* @param age 年龄
* @return int
* @exception RuntimeException 当年龄过大的时候
* @exception IndexOutOfBoundsException 当年龄过小的时候
* @see Student
*/
public int sleep(int age){
new Student();
if(age>100){
throw new RuntimeException();
}
if(age<0){
throw new IndexOutOfBoundsException();
}
return 10;
}
}
IDEA中的javadoc使用:
防止乱码:
JDK内置的3个注解
@Override:限定重写父类方法,该注解只能用于方法
/**
* @auther: themyth
*/
public class Person {
public void eat(){
System.out.println("父类eat");
}
}
/**
* @auther: themyth
*/
public class Student extends Person{
/*
@Override的作用:限定重写的方法,只要重写方法有问题,就有错误提示。
*/
@Override
public void eat(){
System.out.println("子类eat");
}
}
@Deprecated:用于表示所修饰的元素(类,方法,构造器,属性等)已过时。通常是因为所修饰的结构危险或存在更好的选择
/**
* @auther: themyth
*/
public class Student extends Person{
/*
@Override的作用:限定重写的方法,只要重写方法有问题,就有错误提示。
*/
@Override
public void eat(){
System.out.println("子类eat");
}
/*
在方法前加入@Deprecated,这个方法就会变成一个废弃方法/过期方法/过时方法
*/
@Deprecated
public void study(){
System.out.println("学习");
}
}
@SuppressWarnings:抑制编译器警告
import java.util.ArrayList;
/**
* @auther: themyth
*/
public class Test02 {
//这是一个main方法,是程序的入口:
public static void main(String[] args) {
@SuppressWarnings("unused")
int age = 10;
int num =10;
System.out.println(num);
@SuppressWarnings({"unused","rwatypes"})
//第一个参数:抑制变量没有被使用的警告,第二个参数:抑制推荐使用泛型的警告
ArrayList a1 = new ArrayList();
}
}
上述age变量没有被使用,ArrayList没有用泛型表示。
实现替代配置文件功能的注解
在servlet3.0之前的配置:
package com.bjsxt.servlet;
import javax.servlet.*;
import java.io.IOException;
public class HelloServlet implements Servlet {
@Override
public void init(ServletConfig servletConfig) throws ServletException {
}
@Override
public ServletConfig getServletConfig() {
return null;
}
@Override
public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {
System.out.println("service方法被调用了...");
}
@Override
public String getServletInfo() {
return null;
}
@Override
public void destroy() {
}
}
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
version="4.0">
<!--配置Servlet-->
<!--配置Servlet的信息-->
<servlet>
<servlet-name>HelloServlet</servlet-name>
<servlet-class>com.bjsxt.servlet.HelloServlet</servlet-class>
</servlet>
<!--配置Servlet的映射路径-->
<servlet-mapping>
<servlet-name>HelloServlet</servlet-name>
<!--http://localhost:8080/01-hello-servlet/hello-->
<url-pattern>/hello</url-pattern>
</servlet-mapping>
</web-app>
自定义注解
【1】自定义注解使用很少,一般情况下都是用现成的注解。
【2】如何自定义注解:
发现定义的注解的声明使用的关键字:@interface,跟接口没有一点关系。
【3】注解的内部:
以@SuppressWarnings为例,发现内部:
这value是属性还是方法?
答案:看上去是无参数方法,实际上理解为一个成员变量,一个属性 ---函数式属性(方法式属性)
无参数方法名字--》成员变量的名字
无参数方法的返回值--》成员变量的类型
这个参数叫 配置参数
无参数方法的类型:基本数据类型(八种),String,枚举,注解类型,还可以是以上类型对应的数组。
PS:如果只有一个成员变量的话,名字尽量叫value。
【4】使用注解:
(1)使用注解的话,如果你定义了配置参数,就必须给配置参数进行赋值操作:
@MyAnnotation(value={"abc","def","hij"})
public class Person {
}
(2)如果只有一个参数,并且这个参数的名字为value的话,那么value=可以省略不写。
@MyAnnotation({"abc","def","hij"})
public class Person {
}
(3)如果你给配置参数设置默认的值了,那么使用的时候可以无需传值:
public @interface MyAnnotation2 {
String value() default "abc";
}
使用:
@MyAnnotation2
@MyAnnotation({"abc","def","hij"})
public class Person {
}
(4)一个注解的内部是可以不定义配置参数的:
public @interface MyAnnotation3 {
}
内部没有定义配置参数的注解--》可以叫做标记
内部定义配置参数的注解--》元数据
【5】注解的使用:
现在只学习注解的大致技能点,具体怎么应用 后面慢慢学习。
元注解
元注解是用于修饰其它注解的注解。
举例:
JDK5.0提供了四种元注解:Retention, Target, Documented, Inherited
@Retention
用于修饰注解,用于指定修饰的那个注解的生命周期,@Rentention包含一个RetentionPolicy枚举类型的成员变量,使用@Rentention时必须为该value成员变量指定值:
➢RetentionPolicy.SOURCE:在源文件中有效(即源文件保留),编译器直接丢弃这种策略的注释,在.class文件中不会保留注解信息
案例:
反编译查看字节码文件:发现字节码文件中没有MyAnnotation这个注解:
➢RetentionPolicy.CLASS:在class文件中有效(即class保留),保留在.class文件中,但是当运行Java程序时,他就不会继续加载了,不会保留在内存中,JVM不会保留注解。如果注解没有加Retention元注解,那么相当于默认的注解就是这种状态。
案例:
反编译看字节码文件,字节码文件中带有MyAnnotation注解:
➢RetentionPolicy.RUNTIME:在运行时有效(即运行时保留),当运行 Java程序时,JVM会保留注释,加载在内存中了,那么程序可以通过反射获取该注释。
@Target
用于修饰注解的注解,用于指定被修饰的注解能用于修饰哪些程序元素。
@Target也包含一个名为value的成员变量。
案例
import java.lang.annotation.Target;
import static java.lang.annotation.ElementType.*;
@Target({TYPE,CONSTRUCTOR,METHOD})//类 构造器 方法
public @interface MyAnnotation4 {
}
使用:
因为此时Target里面没有传入FIELD参数,所以MyAnnotation4不能修饰属性。
@Documented(很少)
用于指定被该元注解修饰的注解类将被javadoc工具提取成文档。默认情况下,javadoc是 不包括注解的,但是加上了这个注解生成的文档中就会带着注解了
案例:如果:Documented注解修饰了Deprecated注解,
那么Deprecated注解就会在javadoc提取的时候,提取到API中:
@Inherited(极少)
被它修饰的Annotation将具有继承性。如果某个类使用了被
@Inherited修饰的Annotation,则其子类将自动具有该注解。
案例:
注解:如果MyAnno注解使用了@Inherited之后,就具备了继承性,那么相当于子类Student也使用了这个MyAnno