【JavaSE】Java注解
什么是注解
我们最早使用的注解有:方法重写 @Override,在编译期间进行硬性检测,加在方法上就表明该方法是从父类重写过来的。
Java 注解(Annotation)又称 Java 标注,它可以用来对类、方法、属性、参数、包等进行标注,然后让编译器或运行时其他类进行解析,完成某个功能,注解也可以编译到字节码文件中。 当然它也支持自定义 Java 标注。
内置注解
Java 语言中已经定义好的注解。
@Override - 检查该方法是否是重写方法。如果发现其父类,或者是引用的接口中并没有该方法时,会报编译错误。
@Deprecated - 标记过时方法。如果使用该方法,会报编译警告。
@SuppressWarnings - 指示编译器去忽略注解中声明的警告。
@FunctionalInterface 用于指示被修饰的接口是函数式接口。
元注解
元注解是 java API 提供的,是用于修饰注解的注解,通常用在注解的定义上。
@Target(ElementType.METHOD) // 定义这个注解只能用在方法上
@Retention(RetentionPolicy.SOURCE) // 定义这个注解在源文件中有效(编译期间)
public @interface Override {
}
@Retention - 标识这个注解怎么保存,是只在代码中,还是编入 class 文件中,或者是在运行时可以通过反射访问。
@Documented - 标记这些注解是否包含在用户文档中。
@Target - 标记这个注解应该是哪种 Java 成员。
@Inherited - 标记这个注解是继承于哪个注解类(默认注解并没有继承于任何类)
@Repeatable - 标识某注解可以在同一个声明上使用多次。
重点掌握
@Target:用于描述注解的使用范围(即:被描述的注解可以用在什么地方. ElementType.TYPE 可以应用于类的任何元素。
ElementType.CONSTRUCTOR 可以应用于构造函数。
ElementType.FIELD 可以应用于字段或属性。
ElementType.LOCAL_VARIABLE 可以应用于局部变量。
ElementType.METHOD 可以应用于方法级注释。
ElementType.PACKAGE 可以应用于包声明。
ElementType.PARAMETER 可以应用于方法的参数。
@Retention:@Retention 定义了该注解被保留的时间长短:某些注解仅出现在源代码中,而被编译器丢弃;而另一些却被编译在 class 文件中;编译在 class文件中的注解可能会被虚拟机忽略,而另一些在 class 被装载时将被读取(请注意并不影响 class 的执行,因为注解与 class 在使用上是被分离的)。用于描述注解的生命周期(即:被描述的注解在什么范围内有效)取值有:
1.SOURCE:在源文件中有效(即源文件保留)
2.CLASS:在 class 文件中有效(即 class 保留)
3.RUNTIME:在运行时有效(即运行时保留)
自定义注解
对注解进行定义:
package annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface NotNull {
String message() default "";
int length() default 0;
String lengthmessage() default "";
}
对注解进行使用:
package annotation;
public class User {
private int num;
@NotNull(length = 2, message = "名字不能为空", lengthmessage = "名字不能小于2位")
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getNum() {
return num;
}
public void setNum(int num) {
this.num = num;
}
}
对注解进行解析:
package annotation;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
public class Test {
public static void main(String[] args) throws NoSuchMethodException, SecurityException, Exception {
User user = new User();
user.setName("j");
Field[] fields = user.getClass().getDeclaredFields(); // 通过反射拿到类中所有的属性
for (Field field : fields) { // 循环所有的属性
NotNull notNull = field.getAnnotation(NotNull.class); // 获取属性上的指定的注解
if (notNull != null) {
// 通过name属性名字获得对应的get方法名字,再用get方法名字获得方法
Method m = user.getClass().getMethod("get" + getMethodName(field.getName()));
Object obj = m.invoke(user); // 调用获得到的方法,获得返回值
if (obj == null) {
System.err.println(field.getName() + notNull.message()); // 获取注解属性值
throw new NullPointerException(notNull.message());
} else {
if (String.valueOf(obj).length() < (notNull.length())) {
System.err.println(field.getName() + notNull.lengthmessage());
}
}
}
}
}
/**
* 把一个字符串的第一个字母大写
*/
private static String getMethodName(String fildeName) throws Exception {
byte[] items = fildeName.getBytes();
items[0] = (byte) ((char) items[0] - 'a' + 'A');
return new String(items);
}
}