什么是注解(Anotition)?
注解的定义
- Anotion 是从jdk5.0之后引入的新技术
- Anotion的作用:
- 不是程序本身,可以对程序作出解释 ,这点和我们代码中的注解类似(comment)
- 可以对其他程序(比如编译器)所解释执行,读取
- Annotion的格式
- 注解是以 @注解名 在代码中存在,还可以添加一些参数值,例如@SuppressWarnings(value = “uncheck”)
- Anotition的使用场景?
- 可以在package,class,method,field 上面,相当于给他们添加了额外的扩展辅助属性,我们可以通过反射机制实现对这些元数据的访问,动态的去获取值,而不用对代码本身做出改变
内置注解
@Override :
定义在java.lang.Override 中。此注解适用于修辞方法,表示一个方法声明打算重写超类中的另一个方法声明
我们在实现接口和抽象类的方法时,方法上就会自动添加该注解
public class Operation implements Runnable {
@Override
public void run() {
}
}
class scheduler extends Operation1{
@Override
public void get() {
}
}
@Target(value=METHOD)
@Retention(value=SOURCE)
public @interface Override
表示方法声明旨在覆盖超类型中的方法声明。如果使用此注释类型注释方法,则除非至少满足以下条件之一,否则需要编译器生成错误消息:
-
该方法将覆盖或实现在超类型中声明的方法。
-
该方法具有与Object中声明的任何公共方法的覆盖相同的签名。
-
从以下版本开始:
1.5
@Deprecated:
定义在java.lang.Override 中。此注解适用于修辞方法,表示不建议使用的方法,已过期了方法,或者有更好的方法作为替代
这样的注解修饰的方法,我们在调用的时候会出现下划线
@Documented
@Retention(value=RUNTIME)
@Target(value={CONSTRUCTOR,字段,LOCAL_VARIABLE,METHOD,PACKAGE,PARAMETER,TYPE})
public @interface 已过时的
注释@Deprecated的程序元素是程序员不鼓励使用的程序元素,通常是因为它是危险的,或者因为存在更好的替代方法。 编译器在不被弃用的代码中使用或覆盖不推荐使用的程序元素时发出警告。
-
从以下版本开始:
1.5
@SuppressWarnings(“all”)
定义在java.lang.Override 中。此注解适用于修辞方法,用来抑制编译时的警告信息,与前两个注解不同的是,这个注解需要添加参数才能正确使用,这些参数都是已经定义好了的,我们有选择行的使用就好
- @SuppressWarnings(“all”)
- @SuppressWarnings(“unchecked”)
- @SuppressWarnings(value={“unchecked”,“deprecation”})
@Target(value={TYPE,字段,METHOD,PARAMETER,CONSTRUCTOR,LOCAL_VARIABLE})
@Retention(value=SOURCE)
public @interface SuppressWarnings
表示在注释元素(以及注释元素中包含的所有程序元素)中应该抑制命名的编译器警告。请注意,给定元素中抑制的一组警告是所有包含元素中抑制的警告的超集。例如,如果您注释一个类来抑制一个警告并注释方法来抑制另一个警告,则两个警告将在该方法中被抑制。
作为一种风格,程序员应该始终将这个注释用于最有效的嵌套元素。 如果要在特定方法中抑制警告,则应该注释该方法而不是其类。
-
从以下版本开始:
1.5
元注解
元注解的作用就是负责注解其他注解的,通过元注解,我们可以实现自定义注解类,Java的很多开源框架底层都是使用反射加注解的方式实现的
Java定义了4个标准的meta-anotition类型,用来对其他的注解类型进行说明
这个包都位于 java.lang.anotition包下
@Target:
用于描述注解的使用范围,被描述的注解可以用在什么地方
ANNOTATION_TYPE 注解类型声明 |
---|
CONSTRUCTOR 构造函数声明 |
字段 字段声明(包括枚举常数) |
LOCAL_VARIABLE 局部变量声明 |
METHOD 方法声明 |
PACKAGE 包装声明 |
PARAMETER 正式参数声明 |
TYPE 类,接口(包括注释类型)或枚举声明 |
TYPE_PARAMETER 键入参数声明 |
TYPE_USE 使用类型 |
@Retention:
表示需要在什么级别保存该注解信息,用于描述注解的生命周期
CLASS 注释将由编译器记录在类文件中,但VM不需要在运行时保留。 |
---|
RUNTIME 注释将由编译器记录在类文件中,并由VM在运行时保留,因此可以反射读取。 |
SOURCE 注释将被编译器丢弃。 |
@Document:
说明该注解会被包含在javadoc包里
@Inherited:
说明子类可以继承父类的该注解
自定义注解
使用@iterface自定义注解时,自动继承了java.lang.annotation.Annotation接口
-
用@iterface 来声明一个注解
-
public @interface 注解名{注解的内容及参数}
-
其中的每一个没有方法体的方法就是声明了一个配置参数
-
方法的名称就是参数名
-
返回值类型就是参数的类型(返回值只能是基本类型,class,int,string)
-
可以通过default来声明参数的默认值
-
如果只有一个参数成员,一般参数用为value 在传参的时候也不需要再指定
-
注解必须要有值,我们定义注解时,经常使用空字符串,0作为默认值
//自定义注解使用
public class Deprecatedtest{
//我们自定义的注解将作用域声明与字段,就在字段上使用
//注解如果参数,如果没有默认值,我们就必须要传,如果没有则必须要传入参数,default 代表参数默认值
@customAnnotition(id=1,name = "码上跳伦巴")
public void test(){
}
}
@Target({ElementType.ANNOTATION_TYPE,ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@interface customAnnotition{
@SuppressWarnings("all")
int id();
String name();
String school() default "北京邮电大学";
}
使用反射和注解完成类和字段的映射关系ORM
public class ReflectAndAnno {
public static void main(String[] args) throws Exception {
//通过反射获得注解
Class<?> aClass = Class.forName("cn.hhw.jvm.person");
Annotation[] annotations = aClass.getAnnotations();
for (Annotation annotation : annotations){
System.out.println(annotation);
}
//获得注解的值
Tabletest annotation = aClass.getAnnotation(Tabletest.class);
String value = annotation.value();
System.out.println(value);
//获得自定义字段的值
getFields(aClass,"id");
getFields(aClass,"name");
getFields(aClass,"age");
}
public static void getFields(Class<?> aclClass,String fieldName) throws NoSuchFieldException {
Field id = aclClass.getDeclaredField(fieldName);
FieldsTest fieldsTest = id.getAnnotation(FieldsTest.class);
String columnName = fieldsTest.columnName();
String columnType = fieldsTest.columnType();
int length = fieldsTest.length();
System.out.println(columnName+"\t"+columnType+"\t"+length);
}
}
@Tabletest("db_person")
class person{
@FieldsTest(columnName = "db_id",columnType = "varchar",length = 5)
int id;
@FieldsTest(columnType = "db_name",columnName = "varchar",length = 20)
String name;
@FieldsTest(columnName = "db_age",columnType = "int",length = 5)
int age;
}
//类名注解
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@interface Tabletest{
String value();
}
//属性字段注解
@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@interface FieldsTest{
String columnName();
String columnType();
int length();
}
运行结果如下
注解在很多框架底层实现很常见,大家在查看源码是应该会经常遇见,使用的方法也很广泛