Java注解是什么?
Java注解(Annotation)就是一种java标注,并且能够携带数据,是在JDK5.0被引入的。
Java的注解可以标注Java语言中的类、变量、方法、参数、包等等。
值得注意的是:上面所说的Java注解只是一种标注,所以注解需要配合反射来使用才能发挥出强大作用。
注解的成员变量只支持八种基本数据类型(byte、short、int、long、float、double、char、boolean)、String、Class、Enum、Annotation。
还有的就是,所有的注解都是Annotation接口的实现类,可以把Annotation接口看成是所有注解的超类。
java内置的注解
java.lang包中注解
-
@Override - 检查该方法是否是重写方法。如果发现其父类,或者是引用的接口中并没有该方法时,会报编译错误。
Target(ElementType.METHOD)//代表这个注解只能标注在方法上 @Retention(RetentionPolicy.SOURCE)//代表这个注解只在源代码中有效 public @interface Override { }
-
@Deprecated - 标记过时方法。如果使用该方法,会报编译警告。
@Documented @Retention(RetentionPolicy.RUNTIME)//代表这个注解可以保留到运行期间 @Target(value={CONSTRUCTOR, FIELD, LOCAL_VARIABLE, METHOD, PACKAGE, PARAMETER, TYPE})//代表这个注解可以标注在构造方法、成员变量、局部变量、成员方法、包、参数以及类上 public @interface Deprecated { }
-
@SuppressWarnings - 指示编译器去忽略注解中声明的警告。
@Target({TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE}) @Retention(RetentionPolicy.SOURCE) public @interface SuppressWarnings { String[] value(); }
java.lang.annotation中的注解
下面四个注解也称**元注解(即标注在注解上的注解)**
-
@Retention - 标识这个注解怎么保存,是只在代码中,还是编入class文件中,或者是在运行时可以通过反射访问。
@Documented @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.ANNOTATION_TYPE) public @interface Retention { RetentionPolicy value(); }
-
@Documented - 标记这些注解是否包含在用户文档中。
@Documented @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.ANNOTATION_TYPE)//代表这个注解只能标注在注解上 public @interface Documented { }
-
@Target - 标记这个注解应该是哪种 Java 成员。
@Documented @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.ANNOTATION_TYPE) public @interface Target { ElementType[] value(); }
- @Inherited - 标记这个注解是继承于哪个注解类(默认 注解并没有继承于任何子类)
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Inherited {
}
自定义一个注解
/**
* 注解的所有属性都是按照下列类似方法的形式指定的,
* 比如String name() default "myFirstAnnotation"; 意思就是
* 一个类型为String 名字为name 默认值为myFirstAnnotation的属性
*/
@Documented
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
public @interface MyFirstAnnotation {
//注解的名字,可以通过default指定属性的默认值
String name() default "myFirstAnnotation";
//注解的描述
String description();
//注解的取值
String value();
}
上面就是定义了一个可以标注在类或者注解以及方法上的,保留到运行期的注解。但是也仅仅是定义了一个注解而已,一个注解要发挥它自己的作用,还需要反射的配合。
使用自定义注解
//注解直接标注在对应可以标注的东西上就可以了,然后配合反射就可以定义一个注解的作用
@MyFirstAnnotation(value = "class", description = "my class")
public class TestAnnotation{
@MyFirstAnnotation(value = "method", description = "my method")
public void method(){
};
}
什么是反射?
反射是java中的一种机制,通过这种机制我们能够在运行时获取到一个类的一切信息(继承的类、实现的接口、属性、方法等),以及注解信息和注解所携带的数据。
通过获取到的类信息,我们可以构造一个新的对象、获取到某个对象的属性值、执行某个对象的方法等。
反射的常用API
获取Class对象的三种方法
对象.getClass():这种方式会执行类的初始化,即类静态属性的赋值操作
类名.class:这种方式不会执行类的初始化
Class.forName(全类名):这种方式也会执行类的初始化操作,但是需要知道加载的类的全类名
通过Class对象获取类的常见信息(继承的类、实现的接口等)
//获取这个类上标注的指定的注解类型
public <A extends Annotation> A getAnnotation(Class<A> annotationClass)
//获取这个类上标注的的所有注解,包括继承的
public Annotation[] getAnnotations()
//返回直接存在于此元素上的所有注解
public <A extends Annotation> A getDeclaredAnnotation(Class<A> annotationClass)
//获取继承的父类
public native Class<? super T> getSuperclass()
//获取这个类实现的所有接口
public Class<?>[] getInterfaces()
//获取全类名
public String getName()
//获取类名
public String getSimpleName()
通过Class对象获取类的构造方法
//获取指定的public构造方法
public Constructor<T> getConstructor(Class<?>... parameterTypes)
//获取所有的public构造方法
public Constructor<?>[] getConstructors()
//获取当前类声明的指定方法
public Constructor<T> getDeclaredConstructor(Class<?>... parameterTypes)
//获取当前类声明的所有构造方法
public Constructor<?>[] getDeclaredConstructors()
通过Class对象获取类的属性
//通过属性名获取类中的public的属性
public Field getField(String name)
//获取指定类中的所有public的属性
public Field[] getFields()
//通过属性名,获取指定类中的直接声明的属性
public Field getDeclaredField(String name)
//获取指定类中的直接声明的所有属性
public Field[] getDeclaredFields()
通过Class对象获取类的方法
//通过方法签名来获取类中的public方法
public Method getMethod(String name, Class<?>... parameterTypes)
//获取类中的所有public方法
public Method[] getMethods()
//通过方法签名来获取类中直接声明的方法
public Method getDeclaredMethod(String name, Class<?>... parameterTypes)
//获取类中直接声明的所有方法
public Method[] getDeclaredMethods()
通过注解和反射自己来实现简单@Value注解
定义value注解
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Value {
String value();
}
定义pojo User类
public class User {
@Value("root")
private String username;
@Value("12345678")
private String password;
@Value("25")
private String age;
public User() {
}
@Override
public String toString() {
return "User{" +
"username='" + username + '\'' +
", password='" + password + '\'' +
", age=" + age +
'}';
}
public User(String username, String password, String age) {
this.username = username;
this.password = password;
this.age = age;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getAge() {
return age;
}
public void setAge(String age) {
this.age = age;
}
}
测试并使用注解
public class TestAnnotationForValue {
public static User getUser() throws Exception{
//通过全类名的方式加载类对象
Class<?> userClass = Class.forName("annotation.User");
//获取User的无参构造器
Constructor<?> constructor = userClass.getConstructor();
//通过无参构造器获取一个对象
User user = (User)constructor.newInstance();
//获取User的所有属性
Field[] fields = userClass.getDeclaredFields();
for (Field field : fields) {
//判断属性上是否存在@Value注解
if(field.isAnnotationPresent(Value.class)){
//给予私有对象的访问权限
field.setAccessible(true);
//获取到属性上指定的注解
Value valueAnnotation = (Value)field.getAnnotation(Value.class);
//将注解携带的数据,注入到user对象的属性当中
field.set(user, valueAnnotation.value());
}
}
return user;
}
@Test
public void test() throws Exception {
User user = getUser();
System.out.println(user);
//User{username='root', password='12345678', age=25}
}
}