1、元注释和注释的不同
A、注释:用于为代码提供一个描述性的说明,不会编译到class文件中,只存在于源文件.java文件中
B、元注释:是能用运行的代码,用于修饰类、属性、方法等java元素,会编译到class文件中,能被程序读取
2、元注释最常见的作用
保存数据,替代xml
XML:
<student id="1" name="张三" age="20"/>
Annotation:
@Student(id=1, name="张三", age=20);
3、元注释的三个问题
A、定义元注释
定义名称,有哪些成员
B、使用元注释
为成员赋值
C、读取元注释
将成员的值读取出来
4、定义元注释
和接口差不多
成员以方法的形式来定义,规则如下:
A、方法必须有返回类型,不能有参数,可以有默认值
B、方法的返回值类型只能是基本类型及数组、String以及数组、枚举
C、如果元注释只用一个成员,推荐将成员名定义为value
就像所有类都继承自Object一样,所有的元注释都继承自Annotation接口
案例:
/**
* 定义元注释
* @author Administrator
*/
public @interface Student {
public int id();
public String name();
public int age();
public Sex sex() default Sex.男;
}
5、使用元注释
元注释可以修饰类、成员属性、成员方法、元注释等
案例:
@Student(age = 18, id = 1, name = "张三")
public class Useage {
@Student(age = 19, id = 2, name = "历史", sex = Sex.男)
public String field;
@Student(age = 17, id = 3, name = “王五", sex = Sex.男)
public void mthod(){
}
}
6、读取元注释
使用反射进行读取
修饰谁,向谁要
Class、Field、Method共同的方法:
A、isAnnotationPresent(Student.class)
判断Java元素是否被元注释Student修饰
B、getAnnotation(Student.class)
获取指定的元注释
案例:
/**
* 使用元注释
* @author Administrator
*/
@Student(age = 18, id = 1, name = "张三")
public class Useage {
@Student(age = 19, id = 2, name = "李四", sex = Sex.男)
public String field;
@Student(age = 17, id = 3, name = "王五", sex = Sex.男)
public void method(){
Class c;
}
public static void main(String[] args) throws Exception{
Useage u = new Useage();
Class c = u.getClass();
if(c.isAnnotationPresent(Student.class)){
Student stu = (Student)
c.getAnnotation(Student.class);
System.out.println(stu.id());
System.out.println(stu.name());
System.out.println(stu.age());
System.out.println(stu.sex());
}
Field field = c.getDeclaredField("field");
if(field.isAnnotationPresent(Student.class)){
Student stu = field.getAnnotation(Student.class);
System.out.println(stu.id());
System.out.println(stu.name());
System.out.println(stu.age());
System.out.println(stu.sex());
}
Method method = c.getDeclaredMethod("method");
if(method.isAnnotationPresent(Student.class)){
Student stu = method.getAnnotation(Student.class);
System.out.println(stu.id());
System.out.println(stu.name());
System.out.println(stu.age());
System.out.println(stu.sex());
}
}
}
7、元注释的元注释
A、@Target 用于指定元注释可以修饰哪些Java元素
只有唯一的一个成员value,类型是ElementType枚举数组
可能的值有:
public enum ElementType {
TYPE,
FIELD,
METHOD,
PARAMETER,
CONSTRUCTOR,
LOCAL_VARIABLE,
ANNOTATION_TYPE,
PACKAGE
}
例如:@Target({ElementType.TYPE, ElementType.FIELD, ElementType.METHOD})表示可以修饰类、属性、方法
8、@Retention 决定元注释的值是否能通过反射读取
SOURCE:编译后被丢弃
CLASS:编译后元注释的信息会保留在class文件中,但是运行时无法读取
RUNTIME:编译后元注释的信息会保留在class文件中,并且能实时读取
9、写一个输出对象信息的工具,能自定义属性名和日期格式
A、定义元注释
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Name {
String value();
}
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Format {
String value();
}
B、定义工具类Values
public class Values {
/**
* 打印对象obj中的所有属性值
* @param obj
*/
public static void prints(Object obj) throws Exception{
Class c = obj.getClass();
//获取类中所有的属性
Field[] fields = c.getDeclaredFields();
//循环遍历,打印出所有的属性值
if(fields != null){
for(Field field : fields){
field.setAccessible(true);//开放权限
String name = null;
//field是否被Name修饰
if(field.isAnnotationPresent(Name.class)){
//读取@Name中的value值
name = field.getAnnotation(Name.class).value();
}else{
//否则就输出属性名
name = field.getName();
}
String value = null;
if(field.isAnnotationPresent(Format.class)){
String pattern = field.getAnnotation(Format.class).value();
DateFormat df = new SimpleDateFormat(pattern);
value = df.format(field.get(obj));
}else{
value = field.get(obj).toString();
}
System.out.println(name + "=" + value);
}
}
}
}
C、定义测试用的Java实体类
/**
* 产品
* @author Administrator
*/
public class Product {
@Name("产品编号")
private int pid;
@Name("名称")
private String name;
private double price;
@Name("生产日期")
@Format("yyyy年MM月dd日")
private Date date;
public Product() {
// TODO Auto-generated constructor stub
}
public Product(int pid, String name, double price, Date date) {
super();
this.pid = pid;
this.name = name;
this.price = price;
this.date = date;
}
}
public class Employee {
private int eid;
private String name;
@Name("爱好")
private String hobby;
@Format("yyyy/MM/dd HH:mm:ss")
@Name("生日")
private Date birthday;
public Employee() {
// TODO Auto-generated constructor stub
}
public Employee(int eid, String name, String hobby, Date birthday) {
super();
this.eid = eid;
this.name = name;
this.hobby = hobby;
this.birthday = birthday;
}
}
D、测试
public class Test {
public static void main(String[] args) throws Exception {
Product p = new Product(1, "手机", 3000, new Date());
Values.prints(p);
Employee e = new Employee(1, “王二", "编程",
java.sql.Date.valueOf("1996-9-9"));
Values.prints(e);
}
}