定義:
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]接收對象,並解析它。