一、基本介绍
注解(Annotation) 其实就是代码里的特殊标记, 它用于替代配置文件,也就是说,传统方式通过配置文件告诉类如何运行,有了注解技术后,开发人员可以通过注解告诉类如何运行。在Java技术里注解的典型应用是:可以通过反射技术去得到类里面的注解,以决定怎么去运行类。其中三个基本的 Annotation:
- @Override: 限定重写父类方法, 该注解只能用于方法
- @Deprecated: 用于表示某个程序元素(类, 方法等)已过时
- @SuppressWarnings: 抑制编译器警告.
二、自定义注解
1、基本语法
1.注解的定义
定义新的 Annotation 类型使用 @interface 关键字(myeclipase有模板)
public @interface DbInfo {
//内容
}
2.注解属性的声明
注解属性的作用是,原来写在配置文件中的信息,可以通过注解的属性进行描述。注解(Annotation) 的属性声明方式:String name();属性默认值声明方式:String name() default “xxx”;
public @interface MyAnnotation {
//注解可以使用如下类型配置注解包含的信息
String name();//字符串
String password() default "123";//带默认值的字符串
double age() default 12;//double型
Gender gender() default Gender.FEMALE;//枚举型
Class clazz();//类类型
MyAnnotation2 my2();//注解类型,(在注解中包含注解)
int[] arr() default {1,2,3};//一元数组类型
Gender[] gs();
}
/*
<x>
<name>xxx</name>
<y>
<password>
</y>
</x>
*/
引用:
@MyAnnotation(name="老张",age=37,gender=Gender.MALE,clazz=String.class,my2=@MyAnnotation2(name="xxx"),arr={2,3,4},gs={Gender.FEMALE,Gender.MALE})
public void doaa(){
}
附加:
public enum Gender {
MALE,FEMALE;
}
注意:
特殊属性value:如果注解中有一个名称value的属性,那么使用注解时可以省略value=部分,如@MyAnnotation(“xxx")
public @interface MyAnnotation3 {
String[] value();
}
在引用时
//名称为value的属性可以直接赋值
@MyAnnotation3("bb")
public void dobb(){
}
2、元注解
元 Annotation指修饰Annotation的Annotation。JDK中定义了如下元Annotation:
1.@Retention
@Retention 只能用于修饰一个 Annotation 定义, 用于指定该 Annotation 可以保留的域, @Rentention 包含一个 RetentionPolicy 类型的成员变量, 通过这个变量指定域。
RetentionPolicy.CLASS | 编译器将把注解记录在 class 文件中. 当运行 Java 程序时, JVM 不会保留注解. 这是默认值 |
RetentionPolicy.RUNTIME | 编译器将把注释记录在 class 文件中. 当运行 Java 程序时, JVM 会保留注解. 程序可以通过反射获取该注释 |
RetentionPolicy.SOURCE | 编译器直接丢弃这种策略的注释 |
2.@Target
@Target指定注解用于修饰类的哪个成员. @Target 包含了一个名为 value,类型为ElementType的成员变量。
如:指定某个注解注解只能用来修饰方法
@Target({ElementType.METHOD})
public @interface DbInfo {
}
那么在使用该注解时只能在方法中使用,如果不指定,那么在哪都能用(具体,查文档ElementType)
3.@Documented
@Documented用于指定被该元 Annotation 修饰的 Annotation 类将被 javadoc 工具提取成文档.
4.@Inherited
@Inherited: 被它修饰的 Annotation 将具有继承性.如果某个类使用了被 @Inherited 修饰的 Annotation, 则其子类将自动具有该注解,即即使不写该注解,因为它继承于一个被该注解修饰的类,所以它依然有该注解内容。
如:
@Inherited
public @interface DbInfo {
String url() default "jdbc:mysql://localhost:3306/test";
String username() default "root";
String password() default "root";
}
引用该注解的类:
public class JdbcUtils {
@DbInfo(url="jdbc:mysql://localhost:3306/test",username="flx",password="root")
public void aa(){
}
}
继承该类的类:
public class JdbcUtils2 extends JdbcUtils {
@Override
public void aa() {//该方法中依然有父类中的注解
// TODO Auto-generated method stub
super.aa();
}
}
三、应用
1、通过注解的方法进行数据库的连接
自定义注解:
//java--->class--->jvm()
@Retention(RetentionPolicy.RUNTIME)//这句话一定要加,不然在程序运行时获取不到注解内容
public @interface DbInfo {
String url() default "jdbc:mysql://localhost:3306/test";
String username() default "root";
String password() default "root";
}
数据库连接类:
public class JdbcUtils {
@DbInfo(url="jdbc:mysql://localhost:3306/test",username="flx",password="root")
public static Connection getConnection(String url,String username,String password){
//在这里不写具体代码,该方法就是连接数据库的方法
System.out.println(url);
System.out.println(username);
System.out.println(password);
return null;
}
}
通过反射机制获取注解中的内容:
public class Demo {
/**
* @param args
* @throws Exception
* @throws SecurityException
*/
public static void main(String[] args) throws SecurityException, Exception {
Class clazz = JdbcUtils.class;
Method method = clazz.getMethod("getConnection", String.class,String.class,String.class);
DbInfo di = method.getAnnotation(DbInfo.class);
String url = di.url();
String username = di.username();
String password = di.password();
method.invoke(null, url,username,password);//运行进行数据库连接的方法
}
}
2、注入bean的属性
其中bean为:
public class Person {
private String name;
private int age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
定义的注解为:
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@Retention(RetentionPolicy.RUNTIME)
public @interface InjectPerson {
String name();
int age();
}
注入代码为:
public class PersonDao {
//1.将其注入到属性中
@InjectPerson(name="老王",age=23)
private Person person;
public Person getPerson() {
return person;
}
//2.将其注入到set方法中
@InjectPerson(name="老张",age=23)
public void setPerson(Person person) {
this.person = person;
}
}
1.将其注入到属性中
import java.beans.IntrospectionException;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
public class Test2 {
public static void main(String[] args) throws Exception {
//1.得到需要注入的属性
Field f = PersonDao.class.getDeclaredField("person");
//2.得到属性需要的 类型
Class clazz = f.getType();
//3.创建person
Person person = (Person) clazz.newInstance();
//4.反射属性的注解,
InjectPerson inject = f.getAnnotation(InjectPerson.class);
//5.并用注解的信息填充person
Method ms [] = inject.getClass().getMethods();
for(Method m : ms){
String methodName = m.getName(); //name( ) age()
//看person对象上有没有注解与之对应的属性
try{
PropertyDescriptor pd = new PropertyDescriptor(methodName,Person.class);
Method set = pd.getWriteMethod(); //setname setage
set.invoke(person, m.invoke(inject, null));
}catch (Exception e) {
continue;
}
}
//6.把person赋给dao
PersonDao dao = new PersonDao();
f.setAccessible(true); //person
f.set(dao, person);
System.out.println(dao.getPerson().getAge());
System.out.println(dao.getPerson().getName());
}
}
2.将其注入到set方法中
import java.beans.IntrospectionException;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
public class Test {
public static void main(String[] args) throws Exception {
//1.得到要注入的属性
PropertyDescriptor pd = new PropertyDescriptor("person",PersonDao.class);
//2.得到要注入的属性需要的类型
Class clazz = pd.getPropertyType(); //Person
//3.创健属性需要的对象
Object person = clazz.newInstance();
//4.得到属性的写方法
Method setPerosn = pd.getWriteMethod();
//5.反射出方法上声明的注解
InjectPerson inject = setPerosn.getAnnotation(InjectPerson.class);
//6.得到注解上声明的信息,填充person对象
Method[] methods = inject.getClass().getMethods();
for(Method m : methods){
String methodName = m.getName(); //name or age
try{
Field f = Person.class.getDeclaredField(methodName);
Object value = m.invoke(inject, null); //得到注解上配置的属性的值
f.setAccessible(true);
f.set(person, value);
}catch (Exception e) {
continue;
}
}
//7.把填充了数据的person通过setPerson方法整到personDao对象上
PersonDao dao = new PersonDao();
setPerosn.invoke(dao, person);
System.out.println(dao.getPerson().getName());
}
}