这篇博文详细的讲解一下Java的注解,因为Java的注解真是太重要了基本上现在市面上的很多框架都用注解来简化使用者的使用,比如数据库事物控制,根本就不需要什么开启事务关闭事物,一个注解搞定。
1、注解分类:
a、按运行机制分
源码注解:注解只在源码中存在,编译成.class文件就不存在了。
编译时注解:注解在源码和.class中都存在(@Override、@Deprecated、@Suppvisewarnings)
运行时注解;在运行阶段还起作用,甚至会影响运行逻辑的注解。
b、按来源分,有如下三类
JDK自带的注解:Java目前只内置了三种标准注解:@Override(表明覆写父类的方法)、@Deprecated(表明方法过期,不再推荐使用)、@SuppressWarnings(表明去除什么类型的警告),以及四种元注解:@Target、@Retention、@Documented、@Inherited.
第三方注解:用的和接触的最多的注解,比如spring,hibernate的
自定义注解:也可以看做是我们编写的注解,其他的都是他人编写的注解
c、Java的元注解才是最厉害的
自定义注解就靠元注解
2、自定义注解的语法要求
@Target({ElementType.METHOD,ElementType.Type})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
//使用@interface关键字定义注解
public @interface Description{
//成员以无参无异常方式声明
String desc();
String author();
//可以用default为成员指定一个默认值
int age() default 18;
}
成员类型是受限的,合法的类型包含原始类型及String,Class,Annotation,Enumeration
如果注解只有一个成员,则成员名必须为value(),在使用是可以忽略成员名和赋值号=
注解类可以没有成员,没有成员的注解称为标识注解
3、下面四个皆为元注解
@Target({ElementType.METHOD,ElementType.Type})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
3-1:@Target
是注解的作用域:标识该注解可以作用于一个类中的哪些属性及方法上,如果作用域类型有多个,用
英文逗号分隔,下面是注解的作用域列表:
CONSTRUCTOR:构造方法声明
FIELD:字段声明
LOCAL_VARIABLE:局部变量声明
METHOD:方法声明
PACKAGE:包声明
PARAMETER:参数声明
TYPE:类,接口
3-2:@Retention 表示该注解的生命周期
SOURCE:只在源码显示,编译时会丢弃
CLASS:编译时会记录到class,运行时忽略
RUNTIME:运行时存在,可以通过反射读取
3-3:Inherited
此注解是标识性的元注解,表示当前注解可以由子注解来继承
3-4:@Documented
表示生成javadoc的时候会包含注解
4、使用自定义注解
使用注解的语法:
@<注解名>(<成员名>=<成员值>,<成员名>=<成员值>,<成员名>=<成员值>,...)
@Description(desc="I am eyeColor",author="forever",age=18)
public String eyeColor(){
return "red";
}
注解的定义看起来很像接口的定义,事实上,与其他任何Java接口一样,注解也将会编译成class文件。
定义注解时,会需要一些元注解(meta-annotation),如@Target和@Retention。
@Target用来定义你的注解将用于什么地方(例如是一个方法或一个域)。
@Retention用来定义该注解在哪一个级别可用,在源代码(SOURCE)、类文件中(CLASS)或者运行时(RUNTIME)
5、解析注解
通过反射获取类、函数或成员上运行时注解信息,从而实现动态控制程序运行的逻辑。
public static void main(String[] args){
//使用类加载器加载类
try{
Class c = Class.forName("cn.myforever.Test");
//找到类上面的注解
boolean isExist=c.isAnnotationPresent(Description.class);
if(isExist){
//拿到注解实例
Description d =(Description)c.getAnnotation(Description.class);
System.out.println(d.value());
}
}catch(ClassNotFoundException e){
e.printStackTrace();
}
}
使用forName()方法加载类,并使用isAnnotationPresent(Description.class)判断是否有有注解,若是有的话,用getAnnotation(Description.class)获取注解。
注解的继承只能作用在类上,方法上的注解不会被继承,Interface中的所有注解不会被继承。若是方法或者字段的话要相应的调用方法的isAnnotationPresent。
按我理解的注解,作用就是用在类,字段,方法。。。上,然后使用这个类获方法时可以根据注解去获取一些信息,比如这个类的作用,以及这个类要使用的配置文件什么的.
6、下面举个例子
a、首先创建一个注解
package cn.forever.myAnnotation;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* 这个注解要用于所有的地方
* @author forever
*/
//这里暂时类,方法,和字段
@Target({ElementType.METHOD,ElementType.TYPE,ElementType.FIELD,ElementType.PARAMETER})
//运行期有效
@Retention(RetentionPolicy.RUNTIME)
//子类可以继承(标注型注解)
@Inherited
//可出现在JavaDoc中
@Documented
public @interface Description {
/*
* 成员类型是受限的,合法的类型包含原始类型及String,Class,Annotation,Enumeration
* 如果注解只有一个成员,则成员名必须为value(),在使用是可以忽略成员名和赋值号=
* 注解类可以没有成员,没有成员的注解称为标识注解
*/
//注解名字
String name();
//用途
String desc();
}
b、其次创建一个使用注解的model
package cn.forever.model;
import cn.forever.myAnnotation.Description;
//可以告诉这个表的名字,或者这个类需要引用的配置文件路径什么的
@Description(name="TestModel",desc="我是方法")
public class TestModel {//类
@Description(name="name",desc="我是字段name")
private String name;//字段
public String getName() {
return name;
}
@Description(name="test()",desc="我是方法")
public void test(@Description(name="aaa",desc="我是参数aaa")String aaa,@Description(name="bbb",desc="我是参数bbb")String bbb){
System.out.println("方法");
}
}
c、最后创建一个测试类,使用注解
package cn.forever;
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import cn.forever.model.TestModel;
import cn.forever.myAnnotation.Description;
public class Test {
public static void main(String[] args) {
//类
Class clazz = TestModel.class;
Boolean isExist = clazz.isAnnotationPresent(Description.class);
if(isExist){
Description desc = (Description) clazz.getAnnotation(Description.class);
System.out.println(desc.desc());
System.out.println(desc.name());
}
//字段
Field[] fields =clazz.getDeclaredFields();
for (Field field : fields) {
if(field.isAnnotationPresent(Description.class)){
Description desc2 = (Description) field.getAnnotation(Description.class);
System.out.println(desc2.desc());
System.out.println(desc2.name());
}
}
//方法
Method[] methods = clazz.getMethods();
for (Method method : methods) {
if(method.isAnnotationPresent(Description.class)){
Description desc3 = (Description) method.getAnnotation(Description.class);
System.out.println(desc3.desc());
System.out.println(desc3.name());
//参数
Annotation[][] annotations=method.getParameterAnnotations();
for (Annotation[] annotations2 : annotations) {
for (Annotation annotation : annotations2) {
Description desc4=(Description) annotation;
System.out.println(desc4.desc());
System.out.println(desc4.name());
}
}
}
}
}
}
结语
学会注解,为以后写框架打下基础