一、什么是注解
注解就是代码中的特殊标记,这些标记可以在编译、类加载、运行时被读取,并执行相应的处理。
二、注解的作用
1.编写文档:通过代码里标识的元数据生成doc文档
2.代码分析:使用反射可以通过代码里的元数据进行分析
3.编译检查:通过代码标识的元数据可以让编译器实现最基本的编译检查,ex:@Override
三、最常见的注解
1.@Override
@Override的的作用会告诉编译器这个方法是不是重写父类的,可以帮我们避免一些低级的错误,例如,当我们重写equals()方法的时候,并用上了@Override,如果equals拼写错误,那么就会提示该方法不是重写方法。
2.@Deprecated
过时注解,当我们做java设计的时候,可能有的方法设计的并不是很理想,但为了兼容以前的程序又不能把它删除,那么就可以使用@Deprecated标识,当有人使用这个方法的时候,编译器就会提示这是一个过时的方法(方法名上出现横杠)
3.@SuppressWarning
抑制编译警告注解,可以用来让编译器不给予警告
4.@SafeVarargs
堆污染警告,当把不是泛型的集合赋值一个泛型的集合时候,编译器会警告,这个注解也是用来抑制编译器警告的
5.@Functionallnterface
用来指定该接口是函数式接口
四、自定义注解
1.定义一个注解
注意:定义的成员变量只能是String、数组、Class、枚举、注解等类型
2.使用定义好的注解
注意:注解拥有什么样的属性,在修饰的时候就要给出相应的值
3.默认值
在定义注解属性的时候可以定义一个默认值,那么在使用的时候可以不用给出具体的值。
4.注解属性value
当注解上只有一个属性,且属性命名为value,那么在使用的时候可以直接赋值。
五、元注解
概念:元注解就是描述注解的注解
种类:
1.@Target
用于指定注解的使用范围,例如
ElementType.TYPE 仅用于类、接口、枚举
ElementType.FIELD 仅用于属性
ElementType.METHOD 仅用于方法(非构造方法)
ElementType.CONSTRUCTOR 仅用于构造方法
ElementType.PARAMETER 仅用于方法的参数
ElementType.LOCAL_VARIABLE 仅用于局部变量
ElementType.ANNOTATION_TYPE 仅用于注解
ElementType.PACKAGE 仅用于包
当使用在注解上使用@Target(ElementType.METHOD)时,表示只能在方法上使用此注解,用在其他地方会报错。
2.@Retention
用于指定注解在什么阶段有效,(编译,.class,运行)
RetentionPolicy.SOURCE 仅源文件(.java)阶段有效。
RetentionPolicy.CLASS 源文件(.java)阶段以及字节码文件阶
段(.class)有效。
RetentionPolicy.RUNTIME 源文件、字节码以及运行时都有效。
3.@Documented ------几乎不用
当你用@Documented修饰一个方法、类、包、属性等的时候。通过javadoc命令
生成API文档时,注解也会生成到文档中。默认(不写@Documented时)不会把
注解生成到文档中。
4.@Inherited-------几乎不用
它比较复杂,一旦用了这个注解修饰类。这个类的子类会继承父类的属性和方法。
六、将注解注入到方法上
public class Test1 {
private String name;
private String age;
@MyAnnotation(name = "张三", age = "90")
public void add(String name,String age){
this.name=name;
this.age=age;
}
public String getName() {
return name;
}
public String getAge() {
return age;
}
public static void main(String[] args) {
try {
//通过反射得出该方法
Class clazz=Test1.class;
Method method=clazz.getMethod("add",String.class,String.class);
//获取方法上注解的成员
MyAnnotation annotation=method.getAnnotation(MyAnnotation.class);
String name=annotation.name();
String age=annotation.age();
//将注解上的信息注入到方法上
Object o=clazz.newInstance();
method.invoke(o,name,age);
//验证是否注入成功
Test1 test1=(Test1)o;
System.out.println(test1.getName());
System.out.println(test1.getAge());
} catch (Exception e) {
e.printStackTrace();
}
}
}
运行结果:
张三
90
Process finished with exit code 0
七、将对象注入方法上
1.建立一个Person类,并设置get和set方法
public class Person {
private String name;
private String age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getAge() {
return age;
}
public void setAge(String age) {
this.age = age;
}
}
2.设计获取Person实例的类PersonDAO,并在set方法上使用定义好的注解
public class PersonDAO {
private Person person;
public Person getPerson() {
return person;
}
@MyAnnotation(name = "张三",age ="100")
public void setPerson(Person person) {
this.person = person;
}
}
3.设计一个对象注入的方法
public class Main {
public static PersonDAO injectTools() {
PersonDAO personDAO=new PersonDAO();
try {
//使用PropertyDescriptor来获取想要注入的属性
PropertyDescriptor descriptor = new PropertyDescriptor("person", PersonDAO.class);
//得到注入属性的对象
Person person = (Person) descriptor.getPropertyType().newInstance();
//获取该属性的写方法【setPerson()】
Method method = descriptor.getWriteMethod();
//得到写方法上面的注解
MyAnnotation annotation = method.getAnnotation(MyAnnotation.class);
//得到注解里具体的信息
Method[] methods = annotation.getClass().getMethods();
//遍历注解信息,将注解信息注入到person对象上
for (Method m : methods) {
//得到注解的名字【name或者age】
String name=m.getName();
try {
//假设有与之对应的set方法
PropertyDescriptor descriptor1=new PropertyDescriptor(name,Person.class);
//得到写方法【setName()或者setAge】
Method method1=descriptor1.getWriteMethod();
//得到注解的值
Object o=m.invoke(annotation,null);
//调用Person对象的set方法,将注解上的信息填进去
method1.invoke(person,o);
//如果没有对应的set方法,会捕获异常,直接跳过,继续遍历
} catch (IntrospectionException e) {
continue;
}
}
//将填充完的person,赋值给PersonDAO对象
method.invoke(personDAO,person);
//返回填充完毕的personDAO
return personDAO;
} catch(Exception e){
e.printStackTrace();
}
return personDAO;
}
public static void main(String[] args) {
PersonDAO personDAO=injectTools();;
String name=personDAO.getPerson().getName();
String age=personDAO.getPerson().getAge();
System.out.printf("姓名:%s\n年龄:%s\n",name,age);
}
}
运行结果:
姓名:张三
年龄:100
Process finished with exit code 0
八、将对象注入到成员成员变量上
public static PersonDAO injectTools2(){
PersonDAO personDAO=new PersonDAO();
try {
Field field=PersonDAO.class.getDeclaredField("person");
Person person=(Person)field.getType().newInstance();
MyAnnotation annotation=field.getAnnotation(MyAnnotation.class);
Method[] methods=annotation.getClass().getMethods();
for(Method m:methods){
String name=m.getName();
try {
PropertyDescriptor descriptor=new PropertyDescriptor(name,Person.class);
Method method=descriptor.getWriteMethod();
Object o=m.invoke(annotation,null);
method.invoke(person,o);
} catch (Exception e) {
continue;
}
}
field.setAccessible(true);
field.set(personDAO,person);
return personDAO;
} catch (Exception e) {
e.printStackTrace();
}
return personDAO;
}
九、注解的应用场景
开发servlet时,可以免去配置XML文件,例如:(@WebServlet)