Java注解

Annotations是一种元数据,其作用在于提供程序本身以外的一些数据信息,也就是说Annotation他不会属于程序代码本身,不参与逻辑运算,故而不会对原程序代码的操作产生直接的影响。

一般来说Annotation有如下三种使用情形:

为编译器提供辅助信息 
  — Annotations可以为编译器提供而外信息,以便于检测错误,抑制警告等.
编译源代码时进行而外操作 
  — 软件工具可以通过处理Annotation信息来生成源代码,xml文件等等.
运行时处理 
  — 有一些annotation甚至可以在程序运行时被检测,使用.

所谓注解,就是 注入数据+解释(标识作用)

1、注入数据

通过注解属性注入数据

2、解释或标识

比如@Override标识这个方法是重写的。

一、元注解

元注解:给注解类添加的注解
JDK提供给我们的几种常用元注解:
1、Documented 
Documented 注解表明这个注解应该被 javadoc工具记录. 默认情况下,javadoc是不包括注解的. 但如果声明注解时指定了 @Documented,则它会被 javadoc 之类的工具处理, 所以注解类型信息也会被包括在生成的文档中. 


2、Retention 
这种类型的注解会被保留到那个阶段. 有三个值:

RetentionPolicy.SOURCE 

     这种类型的Annotations只在源代码级别保留,编译时就会被忽略,因此一般用来为编译器提供额外信息,以便于检测错误,抑制警告等.

RetentionPolicy.CLASS 

    这种类型的Annotations编译时被保留,在class文件中存在,但JVM将会忽略,一般用来生成源代码,xml文件等

RetentionPolicy.RUNTIME 

    这种类型的Annotations将被JVM保留,所以它们能在运行时被JVM或其他使用反射机制的代码所读取和使用.


3、Target
定义该注解可定义在什么地方,可选值定义在ElementType枚举中:
--TYPE:类、接口、注解、枚举
--FIELD:成员变量,包括枚举常量
--METHOD:方法
--PARMETER:方法参数上
--CONSTRUCTOR:构造方法
--LOCAL_VARIABLE:局部变量
--ANNOTATION_TYPE:枚举
--PACKAGE:包


4、Inherited 
允许子类继承父类的注解。
这个怎么理解呢,给大家举个列子

首先定义一个注解,给该注解添加@Inherited

@Target(value = { ElementType.TYPE,ElementType }) //该注解可以定义在类、方法上
@Retention(RetentionPolicy.RUNTIME)
@Inherited
public @interface MyAnnotation {

}
@MyAnnotation
public class Father{
	@MyAnnotation
	public void fun() {

	}
}

public class Child extends Father {

	@Override
	public void fun() {

	}
}
测试看看Child类是否继承了MyAnnotation注解
boolean annotationPresent = Child.class.isAnnotationPresent(MyAnnotation.class);
结果:annotationPresent=true
Child类上并没有添加注解,但是Child的父类添加了注解MyAnnotation,因为MyAnnotation是可继承的,所以Child类也就继承了该注解。
注意:只有在类上添加注解时,@Inherited才有效,在方法上添加的注解,子类重写该方法,则被子类重写的方法是不会继承该注解的。
Child类重写了父类中的fun方法,
boolean annotationPresent =Child.class.getMethod("fun").isAnnotationPresent(MyAnnotation.class);
结果:annotationPresent=false


二、定义注解

1、Java中使用@interface声明注解
2、注解支持的数据类型
基本数据类型及其数组、String及String[],枚举,注解,Class

@Target(value = {ElementType.TYPE,ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
@Inherited
public @interface MyAnnotation {
	// 基本数据类型:byte,short,int,long,float,double,char,boolean
	int intTest() default 0;

	// 基本数据类型数组:byte[],short[],int[],long[],float[],double[],char[],boolean[]
	int[] intArrayTest() default {};

	// String
	String strTest() default "";

	// String数组
	String[] strArrayTest() default {};

	// 枚举
	ElementType[] enumType() default {};

	// 注解
	MetaAnnotation anno() default @MetaAnnotation();

	// Class
	Class<?> clsType() default Object.class;

}
如果注解中只有一个属性,使用的时候就可以不用明确写出属性名

@Target(value = {ElementType.TYPE,ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
@Inherited
public @interface SingleFieldAnnotation {
   String value();
}

使用

//原始写法
@SingleFieldAnnotation(value="hello world")
public void method(){

}
//因为只有一个属性,可以不用指定属性名
@SingleFieldAnnotation("hello world")
public void method2(){

}

三、注解的使用相关API

为方便讲解,给大家一个直观的感觉,首先定义2个注解

MyAnnotation.java

@Target(value = { ElementType.TYPE,ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
@Inherited
public @interface MyAnnotation {

}

MyAnnotation2.java

@Target(value = { ElementType.TYPE,ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
@Inherited
public @interface MyAnnotation2 {
    
}

使用注解

@MyAnnotation
public class Father{
	@MyAnnotation
	public void fun() {

	}
}

@MyAnnotation2
public class Child extends Father {

	@MyAnnotation
	public void fun2() {

	}
}
isAnnotationPresent
boolean isAnnotationPresent(Class<? extends Annotation> annotationClass)
如果指定类型的注释存在于此元素上,则返回 true,否则返回 false。
比如:
boolean annotationPresent = Child.class.isAnnotationPresent(MyAnnotation2.class);
Child类上存在MyAnnotation2注解,所以返回true


getAnnotation
<T extends Annotation> T getAnnotation(Class<T> annotationClass)
如果存在该元素的指定类型的注释(包括继承的注解 ),则返回这些注释,否则返回 null。
比如:
MyAnnotation annotation= Child.class.getAnnotation(MyAnnotation.class);
虽然Child类上没有添加MyAnnotation,但是由于Child的父类添加了MyAnnotation注解,MyAnnotation可继承,所以Child也就拥有了该注解。


getDeclaredAnnotation
<T extends Annotation> T getDeclaredAnnotation(Class<T> annotationClass)
如果存在该元素的指定类型的注释(不包括继承的注解 ),则返回这些注释,否则返回 null。
比如:
MyAnnotation annotation= Child.class.getDeclaredAnnotation(MyAnnotation.class);
结果annotation=null;因为Child类上只定义了MyAnnotation2.




getAnnotations
<T extends Annotation> T getAnnotation(Class<T> annotationClass)
返回此元素上存在的所有注释,包括继承的注解
比如:
Annotation[] declaredAnnotations = Child.class.getAnnotation();
//由于MyAnnotation是可以继承的
返回结果有2个注解:MyAnnotation和MyAnnotation2。


getDeclaredAnnotations
Annotation[] getDeclaredAnnotations();
返回直接存在于此元素上的所有注释,不包括继承的注解。
比如:
Annotation[] declaredAnnotations = Child.class.getDeclaredAnnotations();
返回Child类上直接定义的注解,这里只有MyAnnotation2。

四、为什么要使用注解

知道了如何定义注解以及注解的相关API后,我们回过头来想想,注解到底有什么作用呢?

1、标识作用

注解一个非常重要的作用就是标识,JDK中就定义了很多的注解用来起到标识的作用。比如:

@Override 用来表示该方法是继承的或实现接口的。

@Deprecated 用来标识该元素是过时的。

Java框架中的注解是随处可见的,比如SpringMVC中的@Controller,@Service,.....................

2、注入属性

由于注解中可以定义属性,设置属性值,所以如果我们想预先给类或方法注入一些属性值的时候,就可以通过注解来注入。调用者可通过反射来获取注入的属性值。

3、减少耦合度



最后,建议大家多看一些优秀的框架设计,试图弄明白设计者的意图。由于注解的使用离不开反射,所以熟练掌握反射也是开发人员必掌握的技能之一。

另外补充下,与Object是所有类的父类一样,java.lang.annotation.Annotation是所有注解类的父类。






  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值