Java 注解
Java 注解从 Java5 开始提供,用于标识(让编译器检查代码)或者注入信息。Jdk 内置了一套注解,分为基本注解与元注解。
基本注解
基本注解在 java.lang 包下,主要有以下5个:
注解 |
使用 |
@Override |
标识方法为重写方法,覆盖超类中声明的方法 |
@Deprecated |
标识过时方法 |
@FunctionalInterface |
标识函数式接口,让编译器检查接口定义是否符合函数式接口定义 |
@SuppressWarnings |
抑制unchecked警告 |
@SafeVarargs |
抑制堆污染警告 |
元注解
元注解是注解的注解,方便实现自定义注解的功能,主要包括以下几种:
注解 |
使用 |
@Retention |
表示注解保留在源码,字节码或运行期,用枚举类 RetentionPolicy 表示保留的时期,默认是字节码时期 |
@Target |
表示注解的作用范围,例如字段,方法等范围,通过枚举类 ElementType 表示 |
@Documented |
将注解的元素包含到 Javadoc 中去 |
@Inherited |
如果它修饰的注解修饰了一个父类,子类会继承父类的注解 |
@Repeatable |
被它修饰的注解可以同时作用一个对象多次,每次注解可以代表不同的含义 |
@Native |
表示一个字段可能涉及 native code |
自定义注解
注解本身是 Annotation 接口的子接口,注解中的属性相当于接口的方法,因此自定义注解中的属性需要带有括号。
注解中的属性类型可以有以下的类型:
- 基本数据类型
- String
- 枚举类型
- 注解类型
- Class 类型
- 以上类型的数组
一个自定义的注解如下所示,将 @Retention 注解的值设置为 RUNTIME,后续可以通过反射获取注解中的值。
1 2 3 4 5 6 7
| @Retention(RetentionPolicy.RUNTIME) @Inherited @Target({ElementType.TYPE}) public @interface MyAnnotation { String name() default "root"; String password() default "123456"; }
|
自定义注解注入信息
自定义注解后,可以通过反射将注解的属性注入到对象或方法中。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| public class Main {
@MyAnnotation(name = "testName", password = "123456") public static void testMyAnnotation(String name, String password) { System.out.println(name + "***" + password); }
public static void main(String[] args) throws Exception { Class clazz = Main.class; Method method = clazz.getDeclaredMethod("testMyAnnotation", String.class, String.class); boolean annotationPresent = method.isAnnotationPresent(MyAnnotation.class); if (annotationPresent) { MyAnnotation myAnnotation = (MyAnnotation) method.getAnnotation(MyAnnotation.class); method.invoke(null, myAnnotation.name(), myAnnotation.password());
} } }
|
自定义注解注入对象
注解的属性只有上面提到的六种类型,有的时候需要注入的不仅仅是这六种类型数据,而是一个对象。注入对象相对比较麻烦。
定义一个 User 类,一个 InjectUser 注解与一个 UserDao,为UserDao注入User属性。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56
| public class User { private String name; private String password;
public String getName() { return name; }
public void setName(String name) { this.name = name; }
public String getPassword() { return password; }
public void setPassword(String password) { this.password = password; }
@Override public String toString() { return "User{" + "name='" + name + '\'' + ", password='" + password + '\'' + '}'; } }
@Retention(RetentionPolicy.RUNTIME) public @interface InjectUser {
String name(); String password(); }
public class UserDao { private User user;
public User getUser() { return user; }
@InjectUser(name="testName", password = "testPassword") public void setUser(User user) { this.user = user; }
@Override public String toString() { return "UserDao{" + "user=" + user + '}'; } }
|
然后修改 main 方法如下,为 UserDao 类注入 User 对象:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| public static void main(String[] args) throws Exception { PropertyDescriptor descriptor = new PropertyDescriptor("user", UserDao.class); User user = (User) descriptor.getPropertyType().newInstance(); Method method = descriptor.getWriteMethod(); Annotation annotation = method.getAnnotation(InjectUser.class); Method[] methods = annotation.getClass().getMethods(); for (Method m : methods) { String name = m.getName(); try{ PropertyDescriptor descriptor1 = new PropertyDescriptor(name, User.class); Method method1 = descriptor1.getWriteMethod(); Object o = m.invoke(annotation, null); method1.invoke(user, o); }catch (Exception e){ continue; } } UserDao userDao = new UserDao(); method.invoke(userDao, user); System.out.println(userDao.getUser()); }
|