Java注解 又称Java标注,是Java语言5.0版本开始支持加入源代码的特殊语法元数据。
Java语言中的类、方法、变量、参数和包等都可以被标注。Java标注和Javadoc不同,标注有自反性。在编译器生成类文件时,标注可以被嵌入到字节码中,由Java虚拟机执行时获取到标注
Annotation 不能影响程序代码的执行,无论增加、删除 Annotation,代码都始终如一执行
元注解
元注解的作用就是用来注解其它注解,主要有四种元注解
注解 | 描述 |
@Target | 表示注解用在哪里:1.CONSTRUCTOR:构造体声明,2.FIELD域声明或者enum实例,3.LOCAL_VARIABLE局部变量4.METHOD:方法声明,5.PACKAGE:包声明,6.PARAMETER:参数声明,7.TYPE:类,接口或enum声明。如果注解应用于所有的ElementType,那么可以省去@Target |
@Retention | 表示需要在什么级别保存信息,1.SOURCE:注解被编译器丢弃.2.CLASS:注解在class文件中可用,但会被JVM丢弃.3.RUNTIME:JVM将在运行期间也保留注解,可以用过反射读取信息 |
@Documented | 将注解包含在Javadoc中 |
@Inherited | 允许子类继承父类的注解.这里有两个注意点1.如果子类继承父类,并且重写了父类中的带有注解的方法,那么父类方法上的注解是不会被子类继承的。2.如果子类继承父类,但是没有重写父类中带有注解的方法,那么父类方法上的注解会被子类继承,就是说在子类中可以得到父类方法上的注解。即使在注解中没有 @Inherited 也会满足上面情况,但是如果该注解是用来修饰类的,则不满足。 |
案例
定义注解并设定注解只能用于方法,在JVM运行期间保留注解
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface UseCase {
public int id();
public String description() default "no description ";
}
定义一个类并用注解修饰这个类的方法
public class PasswordUtils {
@UseCase(id = 17, description = "Password Must Contain At Least one numeric")
public boolean validatePassword(String password) {
return (password.matches("\\w*\\d\\w*"));
}
@UseCase(id = 48)
public String encryptPassword(String password) {
return new StringBuilder(password).reverse().toString();
}
@UseCase(id=49,description = "New password can't equal previously used ones")
public boolean checkForNewPassword(List<String>prevPasswords,String password){
return !prevPasswords.contains(password);
}
}
输出被注解方法的信息包括id,description
public class UseCaseTracker {
public static void trackUseCases(Class<?> cl) {
for (Method m : cl.getDeclaredMethods()) {
//获取注解
UseCase uc = m.getAnnotation(UseCase.class);
//如果注解存在输出注解信息
if (uc != null) {
System.out.println("find use case : id -> " + uc.id() + ",description -> " + uc.description());
}
}
}
public static void main(String[] args) {
trackUseCases(PasswordUtils.class);
}
}
注解元素
并不是所有的元素都能成为注解元素,如果使用了不合法类型的注解那么编译器会报错,注解可用的元素有
- String
- Class
- enum
- Annotation
- 上述类型的数组
使用注解时如果注解没有默认值必须设定注解元素的值,对于非基本类型的元素不能使用null作为值
综合案例
下面是一个综合案例,利用注释生成JavaBean的表定义sql语句
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface DBTable {
public String name() default "";
}
上述这个注释只能用于Javabean类,用于标识这是一个需要为这个javabean类生成一张表,而name是生成数据库表的名字,如果name为空
name就以JavaBean类的名字作为表名
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface SQLInteger {
String name() default "";
Constraints constraints() default @Constraints;
}
映射属性为int类型,只能用于注释属性
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface SQLString {
int value() default 0;
String name() default "";
Constraints constraints() default @Constraints;
}
映射string类型的属性,只能用于注释属性,value是string的长度
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Constraints {
boolean primaryKey() default false;
boolean allowNull() default true;
boolean unique() default false;
}
用于标识表字段的约束,比如标识这个字段是不是主键索引,是不是唯一索引,允不允许为空,在这里为了方便没有设置外键约束
并且这里提供了默认值可以更方便的使用注解
@DBTable(name = "MEMBER")
public class Member {
//因为sqlString注解域为value,所以直接定义值就可以了
//利用该值设定String的长度
@SQLString(30) String fristname;
@SQLString(50) String lastname;
@SQLInteger Integer age;
//设定字符串长度为30并未主键约束
@SQLString(value = 30,constraints = @Constraints(primaryKey = true))
String handle;
static int memberCount;
public String getFristname() {
return fristname;
}
public String getLastname() {
return lastname;
}
public Integer getAge() {
return age;
}
public String getHandle() {
return handle;
}
}
上述代码中对handle的注解利用了嵌套注解
运行结果如下
CREATE TABLE MEMBER(
FRISTNAME varchar (30) ,
LASTNAME varchar (50) ,
AGE INT ,
HANDLE varchar (30) PRIMARY KEY
) ENGINE=InnoDB DEFAULT CHARSET=utf8 ;