1.Java注解是什么?

注解(Annotation),也叫元数据。一种代码级别的说明。它是JDK1.5及以后版本引入的一个特性,与类、接口、枚举是在同一个层次。它可以声明在包、类、字段、方法、局部变量、方法参数等的前面,用来对这些元素进行说明,注释。(引用自百度百科)

2.注解有什么作用,为什么需要注解?

   注解的作用大致分为三类:

    a.编写文档:通过代码里标识的元数据生成文档。【生成doc文档】

    b.代码分析:通过代码里标识的元数据对代码进行分析。【使用反射】

    c.编译检查:通过代码里标识的元数据让编译器能够实现基本的编译检查【override】


心中有上面的两个概念后,就可以正式进入JAVA注解的学习了。


1.注解的分类

    按运行机制来分,共有三种注解。

    a.源码注解:只在源码中存在,编译成class文件就没有了

    b.编译时注解:只在编译时起作用,注解在源码和class文件中都存在

    c.运行时注解:在运行阶段还会起作用,甚至会影响运行逻辑的注解。

按注解来源来分,也有三种注解。

    a.来自JDK的注解。

    b.来自第三方的注解。

    c.我们自己定义的注解。


2.Java中常见的注解

2.1JDK自带的注解

    JDK自带的注解分为3个,@Override,@Deprecated,@Suppvisewarning.下面用程序说明这三个注解的用法.

2.1.1@Override

定义一个接口Parents.java

<span style="font-size:14px;">package com.example.zhujie;

public interface Parents {
	public void age();
	public void name();
}</span>


定义一个Son.java实现这个接口

<span style="font-size:14px;">package com.example.zhujie;

public class Son implements Parents{

	@Override
	public void age() {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void name() {
		// TODO Auto-generated method stub
		
	}</span>

}


可以看到,编译器自动在age(),name()方法上添上了@Override,童鞋们可以想一下这个@Override有什么含义。。没错,这个的意思就是age(),name()方法已经在Parents接口中定义,你要实现这个接口,必须覆盖接口中的这些方法,它给编译器起一个提示的作用,告诉编译器这几个方法一定在你所实现的接口中存在。


2.1.2@Deprecated

Parents.java

java注解字段必填 java中注解有什么用_java注解字段必填

Son.java

java注解字段必填 java中注解有什么用_面向对象_02

Parents.java中方法的上面有@Deprecated说明下面的这个方法已经过时,意思是这个方法在以后的版本中很可能被删除,最好别用,但其实它是个标注性注解,现在不影响程序,因为目前很有可能有的程序在用这个方法,但你用的时候它会给你警告,并在方法名上划一条线起标识作用。

2.1.3@Suppvisewarning

有矛就有盾,@Suppvisewarning就是来抑制编译器产生警告的。有三种使用@Suppvisewarning的格式.

@SuppressWarnings(“”)
@SuppressWarnings({})
@SuppressWarnings(value={})


示例:


·    @SuppressWarnings("unchecked")


告诉编译器忽略 unchecked 警告信息,如使用List,ArrayList等未进行参数化产生的警告信息。


·    @SuppressWarnings("serial")


如果编译器出现这样的警告信息:The serializable class WmailCalendar does notdeclare a static final serialVersionUID field of type long
          使用这个注释将警告信息去掉。


·    @SuppressWarnings("deprecation")


如果使用了使用@Deprecated注释的方法,编译器将出现警告信息。
          使用这个注释将警告信息去掉。


·    @SuppressWarnings("unchecked", "deprecation")


告诉编译器同时忽略unchecked和deprecation的警告信息。


·    @SuppressWarnings(value={"unchecked", "deprecation"})


等同于@SuppressWarnings("unchecked", "deprecation")


2.2第三方的注解

由于作者的水平原因,并不了解关于第三方注解的一些知识,有兴趣的童鞋可以自己搜索查看。


3.自定义注解

3.1自定义注解的语法


//@interface是定义一个注解所必须的,既把class换成@interface就表示定义的是注解
	public @interface De{
		//声明成员的语法
		String a();
		String b();
		//给成员赋初值的语法
		int c() default 10;
	}

    注意,声明成员时,不能有参数,不能有异常,比如下面的语法就是错误的.


String a(int v) throws Exception;

3.2元注解的语法


@Target({ElementType.METHOD})
	@Rentention(RententionPolicy.RUNTIME)
	@Inherited
	@Documented
	public @interface Fe{
		String a();
		String b();
	}


注解Fe头上的四段代码就是元注解的基本语法,下来分别说明每段代码的作用 和它的参数的类型。

3.2.1@Target({XXX})

    语法格式@Target({ElementType.XXX})

    作用:用于描述注解的作用范围,既限定特定的注解用在特定的地方,凭借它的参数达到这一效果。

    参数XXX包括以下几种情况:

    a.CONSTRUCTOR用于构造函数

    b.FIELD用于描述成员变量

    c.LOCAL_VARIABLE用于描述局部变量

    d.METHOD用于描述方法

    e.PACKAGE用于描述包

    f.PARAMETER用于描述参数

   g.TYPE用于描述类,接口(包括注解类型),或enum声明

3.2.2@Retention

    语法格式@Retention(RetentionPolicy.XXX)

    作用:定义了该Annotation被保留的时间长短:某些Annotation仅出现在源代码中,而被编译器丢弃;而另一些却被编译在class文件中;编译在class文件中的Annotation可能会被虚拟机忽略,而另一些在class被装载时将被读取(请注意并不影响class的执行,因为Annotation与class在使用上是被分离的)。使用这个可以对 Annotation的“生命周期”限制。

参数XXX包括以下几种情况:

    1.SOURCE:在源文件中有效,既在源文件中保留。

既在Class文件中保留。

既在运行时保留。

3.2.3@Inherited

    语法格式:@Inherited

    作用:@Inherited元注解是一个标记注解,如果使用了一个@Inherited修饰的注解用于一个class,则这个注解将被用于这个类的子类。

    注意:@Inherited annotation类型是被标注过的class的子类所继承。类并不从它所实现的接口继承annotation,方法并不从它所重载的方法继承annotation。

3.2.4@Documented

    语法格式:@Documented

    作用:@Documented是一个标注性注解,表示该注解可以被文档化。

3.3使用自定义注解

    使用自定义注解的基本语法如下面的代码所示,包括了注解的定义和使用。

@Target({ElementType.METHOD})
	@Retention(RetentionPolicy.RUNTIME)
	@Inherited
	@Documented
	public @interface Fe{
		String a();
		String b();
	}
	
	
	@Fe(a = "a",b = "b")
	public void test(){
		
	}

    基本语法是@注解名(成员名=成员值,成员名=成员值,......)

3.4解析注解

    基本概念:通过反射获取类,函数,或成员上的运行时注解信息,从而实现动态控制程序运行的逻辑。

    首先定义一个注解,MyAnnotation.java

import java.lang.annotation.*;
@Target({ElementType.METHOD,ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface MyAnnotation{
	String value();
}

    再定义一个使用注解的类,UseAnnotation.java

注意,当一个注解只有一个变量时,推荐变量名为value,使用注解时可以省略变量名和等号


<span style="font-size:18px;">@MyAnnotation("Class Annotation")
public class UseAnnotation {
	@MyAnnotation("Method Annotation")
	public void test(){
		
	}
}</span>


然后开始解析注解,请各位小伙伴注意下面程序中的注释,此程序共说明了如何解析类上的和方法上的注解。


package com.example.annotation;

import java.lang.annotation.Annotation;
import java.lang.reflect.Method;

public class ParseAnnotation {
	
	public static void main(String[] args) throws Exception{
		/**
		 * 解析类上的注解
		 */
		//第一步,使用类加载器加载你需要解析的类(那个类中包含你需要解析的注解)
		Class c = Class.forName("com.example.annotation.UseAnnotation");
		//第二步,判断类上是否有注解
		boolean isExist1 = c.isAnnotationPresent(MyAnnotation.class);
		if(isExist1){
			//第三步,拿到注解的实例
			MyAnnotation myAnnotation1 = (MyAnnotation) c.getAnnotation(MyAnnotation.class);
			//第四步,输出值验证
			System.out.println(myAnnotation1.value());
		}
		
		/**
		 * 第一种方法解析方法上的注解
		 */
		//第一步,首先获取所有方法
		Method[] mes = c.getMethods();
		for(Method mm : mes){
		//第二步,找出那些有注解的方法
			boolean isExist2 = mm.isAnnotationPresent(MyAnnotation.class);
			if(isExist2){
				MyAnnotation myAnnotation2  = mm.getAnnotation(MyAnnotation.class);
				System.out.println(myAnnotation2.value());
			}
		}
		
		/**
		 * 第二种方法解析方法上的注解
		 */
		for(Method mm : mes){
			Annotation[] annotations = mm.getAnnotations();
			for(Annotation a : annotations){
				if(a instanceof MyAnnotation){
					MyAnnotation myAnnotation3 = (MyAnnotation)a;
					System.out.println(myAnnotation3.value());
				}
			}
		}
		
	}
	
}


后记:以上的内容就是一些比较基础的注解知识,看完这篇文章的小伙伴可以去看我的下一篇博客,实战注解,用一个实际的例子加深我们对注解的理解。