Annotation是什么?
在已经发布的JDK1.5(tiger)中增加新的特色叫 Annotation。Annotation提供一种机制,将程序的元素如:类,方法,属性,参数,本地变量,包和元数据联系起来。这样编译器可以将元数据存储在Class文件中。这样虚拟机和其它对象可以根据这些元数据来决定如何使用这些程序元素或改变它们的行为。
Annotation的作用?
Annotation其实就是代码里的特殊标记,它常用于替换配置文件(如web.xml等)。
Annotation的位置?
注解可以加在类、接口、方法、方法参数、字段和本地变量上。
常见的元Annotation?
元Annotation指的是修饰注解的注解。常见的元Annotation有@Retention,@Target,@Documented,
@Inherited:
@Rentention:用于指定该Annotation可以保留的域,
@Rentention包含一个RententionPolicy类型的属性,通过这个属性指定域:
RententionPolicy.CLASS:编译器将把注解记录在Class文件中,当运行java程序时,jvm不会保留注解。这是默认值。
RententionPolicy.RUNTIME:编译器将把注解记录在文件中,当运行java程序时,jvm会保留注解。
RententionPolicy.SOURCE:编译器直接丢弃这种策略的注解。
注:
RententionPolicy.RUNTIME是我们最常用的值。
@Target:指定注解用于修饰注解的哪些成员。属性值是枚举类型ElementType中的某些值。
@Documented:用于指定被该Annotation修饰的Annotation类将被javadoc工具提取成文档。
@Inherited:被它修饰的Annotation将具有继承性,如果某个类使用了被@Inherited修饰的Annotation,则其子类将自动具有该注解。
注解声明
package cn.edu.chd.annotation;
/**
* @author Rowand jj
*
*这是一个注解的示例
*
*
*1.注解接收的类型有:
*String类型,基本数据类型,Class类型,枚举类型,注解类型,以及以上类型的一维数组
*其他类型不可以,比如List list();//这是错误的
*
*2.如果一个属性的名字为value,则调用该注解时可以不指定名字:
*public @interface annotation
*{
* String value();
*}
* 此时,@demo("zhangsan")等价于@demo(value="zhansgan")
*
*/
public @interface MyAnnotation
{
String name();//为这个注解添加了一个名为name的属性
String password() default "123";//配置缺省值
int age() default 13;
Gender gender() default Gender.FEMAIL;//枚举类型,并有默认值
Class clazz();//一个类类型
MyAnnotation2 my2();//注解中嵌套注解
int[] arr() default {1,23,4};//数组
}
使用注解:
@MyAnnotation(name="zhansgan",age=33,clazz=MyAnnotationDemo.class,my2=@MyAnnotation2(like="chifan"))
public void aa()
{
}
应用场景一:使用注解作为配置文件为方法提供运行时的参数
package cn.edu.chd.annotation;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
/**
* @author Rowand jj
*
*保存连接数据库参数的注解
*
*@Retention(RetentionPolicy.RUNTIME)这是指定当前注解的作用域是运行时
*/
@Retention(RetentionPolicy.RUNTIME)
public @interface DBInfo
{
String url() default "jdbc:mysql://localhost:3306/db_test";
String username() default "root";
String password() default "root";
}
package cn.edu.chd.annotation;
import java.lang.reflect.Method;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
public class JDBCUtils
{
@DBInfo(password="sjjhong")
public static Connection getConnection(String url,String username,String password)
throws SQLException
{
return DriverManager.getConnection(url, username, password);
}
/**
* 通过反射技术获取方法上注解的信息
*/
public static void main(String[] args) throws Exception
{
Method method = JDBCUtils.class.getMethod("getConnection", String.class,String.class,String.class);
DBInfo info = method.getAnnotation(DBInfo.class);
String url = info.url();
String password = info.password();
String username = info.username();
// 调用方法
System.out.println(method.invoke(null,url,username,password));
}
}
控制台输出:
com.mysql.jdbc.JDBC4Connection@3bcd288e
成功获取到了参数.
应用场景二:通过注解技术注入对象
package cn.edu.chd.annotation2;
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;
}
}
package cn.edu.chd.annotation2;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@Retention(RetentionPolicy.RUNTIME)
public @interface InjectPerson
{
String name();
int age();
}
package cn.edu.chd.annotation2;
public class PersonDao
{
private Person person;
public Person getPerson()
{
return person;
}
@InjectPerson(name="hehe",age=12)
public void setPerson(Person person)
{
this.person = person;
}
}
package cn.edu.chd.annotation2;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
public class Demo
{
public static void main(String[] args) throws Exception
{
// 1.得到要注入的属性
PropertyDescriptor pd = new PropertyDescriptor("person", PersonDao.class);
// 2.得到要注入的属性需要的类型
Class clazz = pd.getPropertyType();
// 3.创建属性需要的对象
Object p = clazz.newInstance();
// 4.得到属性的写方法
Method setPerson = pd.getWriteMethod();
// 5.反射出方法上声明的注解
InjectPerson inject = setPerson.getAnnotation(InjectPerson.class);
// 6.得到注解上声明的信息,填充person对象
Method[] methods = inject.getClass().getMethods();
for(Method m : methods)
{
String methodName = m.getName();
try
{
Field f = Person.class.getDeclaredField(methodName);
Object value = m.invoke(inject,null);
f.setAccessible(true);
f.set(p, value);
} catch (Exception e)
{
continue;
}
}
// 7.把填充了数据的person通过setPerson方法整到personDao对象上
PersonDao dao = new PersonDao();
setPerson.invoke(dao,p);
System.out.println(dao.getPerson().getName());
}
}
控制台输出:hehe