注解(也被称为元数据),为我们在代码中添加信息提供了一种形式化的方法,使我们可以在稍后某个时刻非常方便的使用这些数据。(通过反射的方式)
java中已经有的注解:
1 @override:表示当前的方法将覆盖超类中的方法(重写方法)
2 @Deprecated:表示已经废弃的方法,使用就会报错
3 @SuppressWarnings:关闭编译器警告信息
基本语法
注解的定义看起来像接口的定义,并且也会被编译称为class文件
@Target(ElementType.METHOD)//表示可以标注的位置信息,此处为方法前
@Retention(RetentionPolicy.RUNTIME)//表示运行时可以获取,通过反射可以获取
public @interface Test {}
public class Testable {
public void execute(){
System.out.println("Executing---");
}
@Test void test(){
execute();
}
public static void main(String[] args) {
final Testable testable = new Testable();
testable.test();
}
}
@Target:用来定义注解放在什么地方(比如放在一个方法,或者是一个域)
@Retention:用来定义注解应用在哪一个级别(SOURCE表示在源代码中,CLASS表示在类文件中,RUNTIME,在运行时)
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface UseCase {
public int id();
public String description() default "no description";
}
id和desctrition的定义类似于方法,但是description元素拥有一个default值,如果在注解某个方法时内有给出description的值,此时就会使用default值
public class PasswordUtils {
@UseCase(id = 47, description = "密码必须至少有一位")
public boolean validatePassword(String password) {
return (password.matches("\\w*\\d\\w*"));
}
@UseCase(id = 48)//在这里并没有给出description的值,所以处理时会使用该元素的默认值
public String encryptPassword(String password) {
return new StringBuilder(password).reverse().toString();//
}
@UseCase(id = 49, description = "不能够使用旧密码")
public boolean checkForNewPassword(List<String> prePassword,String newPassword) {
return !prePassword.contains(newPassword);
}
}
元注解
元注解专职负责其他的注解:
@Retention:SOURCE:被修饰的类,被编译后,丢弃该注解。CLASS:通过反射获取不到
编写注解处理器
在使用注解的过程中,很重要的一点就是使用注解处理器
public class UseCaseTracker {
public static void trackUseCases(List<Integer> useCases, Class<?> cl) {
for (Method m : cl.getDeclaredMethods()) {//获取cl的所有的方法
UseCase uc = m.getAnnotation(UseCase.class);//返回指定类型的注解对象
if (uc != null){
System.out.println("Fount Use Case: " + uc.id() + " " + uc.description());
useCases.remove(new Integer(uc.id()));
}
}
for (Integer i : useCases) {
System.out.println("Not Fount Use Case " + i);
}
}
public static void main(String[] args) {
List<Integer> useCases = new ArrayList<>();
Collections.addAll(useCases, 45, 46, 47, 48, 49, 50);
System.out.println(useCases);
trackUseCases(useCases, PasswordUtils.class);
}
}
注解元素
注解元素可用的类型:所有的基本类型,String,Class,enum,Annotation还有以上类型的数组。
但是不允许使用任何的包装器类型。注解也可以作为元素的类型,也就是说注解可以嵌套
默认值限制
元素不能有不确定的值,也就是说,元素必须要么具有默认值,要么在时用注解的时候提供元素的值
生成外部文件
如果希望提供一些基本的的对象/关系映射功能,能够自动生成数据库,用以存储对象,如果使用注解的话,就可以将所有的信息都保存在源文件中,为此我们需要一些新的注解,用来定义相关联的数据库表的名字,以及与属性相关联的列的名字和SQL类型。
注解的定义:
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface DBTable {
public String name() default "";
}
在@Target注解中指定的每一个ElementType就是一个约束,它告诉编译器,这个自定义的注解只能应用于该类型
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Constrains {
boolean primaryKey() default false;
boolean allowNull() default true;
boolean unique() default false;
}
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface SQLString {
int value() default 0;
String name() default "";
Constrains constrains() default @Constrains;
}
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface SQLInteger {
String name() default "";
Constrains constrains() default @Constrains;
}
注解处理器通过@Constraints注解提取出数据库表的元数据,虽然对于数据库所能提供的所有约束而言,@Constraints注解值表示了它的一个很小的子集,primaryKey(),allowNull(),unique(),元素明智的提供了默认值
这些SQL类型具有name()元素和constraints()元素,后者利用了嵌套注解的功能,constraints()元素的默认值时@Constraints,由于在@Constraints注解类型之后,没有在括号中指明@Constraints中元素的值,因此constraints()元素的默认值实际上就是一个所有元素都为默认值的@Constraint注解
@DBTable(name = "MEMBER")
public class Member {
@SQLString(30)
String firstName;
@SQLString(50)
String lastName;
@SQLInteger
Integer age;
@SQLString(value = 30, constrains = @Constrains(primaryKey = true)) String Handle;
static int memberCount;
public String getFirstName() {
return firstName;
}
public String getLastName() {
return lastName;
}
public Integer getAge() {
return age;
}
public String getHandle() {
return Handle;
}
}
这些注解第一:都使用了嵌入的@Constraint注解的默认值;第二:他们都是用了快捷方式(如果在注解中定义了名字为value的元素,并且在应用该注解的时候,如果该元素时唯一需要赋值的一个元素,那么此时无需使用名-值对的这种语法,只需要在括号内给出value元素所需要的值就可以了)
直接不支持继承
java中的注解时不可以使用extands关键字来继承某个@interface的;