一、什么是注解?
注解:源代码的元数据,代码的标签
本质一:就是一个附属品,依赖其他元素存在(比如类、方法);
本质二:本身没有任何作用,在恰当的时候由外部程序解析产生作用(通过反射);
二、编写并使用自定义注解
自定义注解:
package cn.fllday;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* 自定义注解
* @author gssznb
*
*/
@Documented
@Inherited
@Target({ElementType.FIELD,ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface Init {
public String value() default "hello";
}
创建数据模型并使用注解
package cn.fllday;
/**
* User.java
* 数据模型中使用注解
* @author gssznb
*
*/
public class User
{
private String name;
private String age;
public String getName()
{
return name;
}
@Init(value = "liang")
public void setName(String name)
{
this.name = name;
}
public String getAge()
{
return age;
}
@Init(value = "23")
public void setAge(String age)
{
this.age = age;
}
}
反射获取注解中的数据
package cn.fllday;
import java.lang.reflect.Method;
/**
* 使用构造工厂当作 注解解析器
*
* @author gssznb
*
*/
public class UserFactory {
public static User create() {
User user = new User();
// 获取User类中的所有方法。 (getDeclareMethods)
Method[] methods = User.class.getMethods();
for (Method method : methods) {
if (method.isAnnotationPresent(Init.class)) {
Init init = method.getAnnotation(Init.class);
try {
System.out.println(init.value());
method.invoke(user, init.value());
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
return null;
}
}
}
return user;
}
}
调用方法。和打印值
package cn.fllday;
public class Test {
public static void main(String[] args) {
User u = UserFactory.create();
System.out.println(u.getName());
System.out.println(u.getAge());
}
liang
23
liang
23
}
注解的作用:
- 简化配置
- 增加代码可读性
- 提高系统可维护性
注意:如果自定义注解只有一个成员,则成员必须取名为value(),在赋值时可忽略成员名和赋值号(=)
上面是我运行别人的代码,成功后Ctrl+C/V的,下面是本人亲自操刀,自己理解的。
1、 自定义一个注解(@MyAnnotation本身只是标记)
package com.tanhua.es.annotion;
import java.lang.annotation.*;
@Documented
@Target({ElementType.FIELD,ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnotation {
String value() default "lisi";
int num() default 0;
}
2、有一个Student类,想利用自己写的@MyAnnotation 注解给上面的字段赋值
package com.tanhua.es.pojo;
import com.tanhua.es.annotion.MyAnnotation;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@AllArgsConstructor
@NoArgsConstructor
@Data
public class Student {
@MyAnnotation("zhangsan")
private String name;
private Integer age;
}
3、要想使注解生效,需要通过反射来进行
package com.tanhua.es.annotion;
import com.tanhua.es.pojo.Student;
import java.lang.reflect.Field;
public class MyAnnotationTest {
public static Student create() {
Student student = new Student();
//暴力反射Student类里面的所有字段(包括私有的)
Field[] fields = student.getClass().getDeclaredFields();
//遍历所有字段,看哪些字段上加了@MyAnnotation注解
for (Field field : fields) {
field.setAccessible(true);
MyAnnotation annotation = field.getAnnotation(MyAnnotation.class);
if (annotation != null) {
try {
//将注解里面的值赋值给student对象里的字段
field.set(student, annotation.value());
//field.set(student,annotation.num());
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
}
return student;
}
}
4、通过我们反射后得到的Student对象,和直接new Student对象的打印结果如下:
package com.tanhua.es;
import com.tanhua.es.annotion.MyAnnotationTest;
import com.tanhua.es.pojo.Student;
public class Test {
public static void main(String[] args) {
//必须使用反射才能使注解生效
Student student = MyAnnotationTest.create();
System.out.println(student);//Student(name=zhangsan, age=null)
//未使用反射创建的Student对象,字段没有任何赋值
Student s=new Student();
System.out.println(s);//Student(name=null, age=null)
}
}
5、总结
- 自定义注解>>>>>注解加到Student类对象上(成员变量/方法)>>>>反射得到Student对象里的成员>>>>>>>判断哪些字段上标记了注解>>>>>>>将注解里的值赋给Student的成员
- 直接new Student()是无效的,因为没有走我们写的反射过程