定义:
1:注解也是类如@Test.
2:所有注解的父类,不用继承,都是java.lang.Annotation。
3:注解的定义方式为:
Public @interfaceSomeAnnotation{
}
4:注解可以注解的位置
1:可以注解在其他的注解上。
2:xxx 不是
3:构造
4:字段上
5:局部变量
6:方法
7:包
8:参数
9:类上
5:注解生存的范围
CLASS 默认的停留范围 *.class 编译器将把注释记录在类文件中,但在运行时 VM 不需要保留注释。 |
RUNTIME new SomeClass(); 编译器将把注释记录在类文件中,在运行时 VM 将保留注释,因此可以反射性地读取。 |
SOURCE - 只在源代码中存在,*.java中存在。@overried 编译器要丢弃的注释。 |
作用:
1:在编译时起限制作用。
如以下代码:
public class MyServlet extends HttpServlet {
//限制此方法来自于父类
@Override
public void doGet(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
System.err.println("OKKIOK");
}
}
2:在运行时给反射用的
以下模拟JUNIT运行一个类中的所有添加了@MyTest注解的方法:
第一步:定义一个注解
packagecn.itcast.anno;
importjava.lang.annotation.ElementType;
importjava.lang.annotation.Retention;
importjava.lang.annotation.RetentionPolicy;
importjava.lang.annotation.Target;
@Retention(value=RetentionPolicy.RUNTIME)[W1]
@Target(value={ElementType.METHOD})[W2]
public @interface MyTest {
}
第二步:开发MyUnit类读取添加了注解的方法,并运行它
packagecn.itcast.anno;
importjava.lang.reflect.Method;
importjava.util.Scanner;
import org.junit.Test;
public classMyUnit {
public static void main(String[] args) throws Exception {
Scanner sc = newScanner(System.in);
System.err.println("请输入你要测试的类:");
String clsName = sc.nextLine();
//获取类的字节码
Class cls = Class.forName(clsName);//使用反射
//实例化这个类
Object obj = cls.newInstance();
//遍历所有方法
Method[] ms =cls.getDeclaredMethods();//返回所有自己定义的方法(private|public)
for(Method m:ms){
//判断这个方法上是否存在MyTest这个注解
//System.err.println("方法名:"+m.getName());
boolean boo =m.isAnnotationPresent(MyTest.class);[W3]
//System.err.println(boo);
if(boo){
m.invoke(obj);
}
}
}
}
[W1]指明在运行时存在。
[W2]只可以注解在方法上。
[W3]J判断是否存在某个注解。
-----------------续-------------------------------------
添加了属性的注解
在注解中可以定义属性:
@Retention(RetentionPolicy.RUNTIME)
@Target(value={ElementType.METHOD,ElementType.TYPE})
public @interface MyTest {
String value[W1] ()[W2] default "hello";[W3]
int age() defalut 99;
}
给属性设置值:
/**
* JVM帮助你实例化这个类
*/
@MyTest(value="hello",age=100)
public void aa(){}
以下是定义:
@Retention(RetentionPolicy.RUNTIME)
@Target(value={ElementType.METHOD,ElementType.TYPE})
public @interface MyTest {
String value() default"hello";
int age() default 89;------------------注解,只支持基本数据类型的属性,String,枚举,注解,Class。
String[] names();
}
以下设置值或是调用:
@MyTest(value="hello",age=100,names={"Jack","Rose"})----注意这里,数组的写法是用{}
public void aa(){
}
作用是什么呢:
注解是给框架师用的?
可以对dbutils进行增强。
第一步:定义两个注解:
@Retention(RetentionPolicy.RUNTIME)------在运行时存在
@Target(value=ElementType.TYPE)------作用在类上,写在类上
public @interface Table{
String value() default"";
}
@Retention(RetentionPolicy.RUNTIME)
@Target(value=ElementType.FIELD)-------作用在字段上
public @interface Column {
String value() default"";
}
第二步:给QueryRunner增加一个save方法:
/**
* 添加一个方法直接保存一个对象
*/
public void save(Objectbean[W4] ) {
// 1:获取类名
Class<?> cls = bean.getClass();
// 2:获取上面的注解
if (cls.isAnnotationPresent(Table.class)) {
// 3:获取这个注解的实例
Table table = cls.getAnnotation(Table.class);
// 4:获取上面的value值
String tableName = table.value();
if (tableName.equals("")) {
tableName = cls.getSimpleName().toLowerCase();
}
// 5:组成insert
String insert = "insert into "+ tableName + "(";
String values = " values(";
// 6:遍历所有的字段
Field[] fs = cls.getDeclaredFields();
List<Object> params = newArrayList<Object>();
for (Field f : fs) {
if (f.isAnnotationPresent(Column.class)) {
Column col = f.getAnnotation(Column.class);
// 7:获取列名
String colName = col.value();
if (colName.equals("")) {
colName = f.getName();
}
// 8:写入字段名
if (insert.endsWith("(")) {
insert += colName;
values += "?";
} else {
insert += "," + colName;
values += ",?";
}
// 只要是有@Columns注解,都是数据表的字段
f.setAccessible(true);
try {
params.add(f.get(bean));
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
// 9:加上最后)
insert += ")";
values += ")";
String sql = insert + values;
System.err.println(sql);
this.update(sql,params.toArray());
} else {
throw new RuntimeException("你可能忘记了添加@Table注解");
}
}
[W1]在所有注解中,如果存在一个value这样的属性,则这个属性是默认属性。
[W2]属性
[W3]默认值。
[W4]接收对象,并解析它。