Java 注解编程
一、注解介紹
注解(Annotation) 是 jdk1.5 版本以后引入的一個新特性,注解可以說是類反射的延伸,在一些需要配置文件的應(yīng)用中,可以使用注解替代配置文件,從而提高應(yīng)用的靈活。比如 常見的 @Autowired,@Controller 等。
下面是 Java 底層內(nèi)置的幾個注解
@Override: 只適用于方法,表示重寫父類中的方法
@Deprecated: 表示某各類或方法已過時,比如 Date 類中的 toLocaleString() 方法
@SuppressWarnings: 抑制編譯器的警告
二、元注解
元注解用于修飾注解,用于約束注解的作用范圍,注解級別等,下面是 Java 提供的 4 種元注解
@Target:指定注解使用的位置,@Target 中有一個 ElementType 數(shù)組,因此被 @Target 注解修飾的注解可以在多個位置上使用。下面是 ElementType 枚舉中的一些屬性(只列舉一些常用的屬性)
- TYPE:能在類、接口(包含注解類型)和枚舉類型上使用
- FIELD:只能在屬性上使用
- METHOD:只能在方法上使用
- ……
@Retention:用于表示該注解可以保留的作用域,@Retention 注解包含一個 RetentionPolicy 屬性,通過這個屬性來設(shè)置注解的保留域。RetentionPolicy 是一個枚舉,其中有 3 個屬性,如下
- SOURCE:只在源代碼中顯示,在編譯成 .class 文件的時候會被丟棄
- CLASS:編譯器會把注解記錄在 .class 文件中,當(dāng)程序運(yùn)行時,虛擬機(jī)不會保留該注解
- RUNTIME:當(dāng)程序運(yùn)行時,也會被保留,因此可以通過反射技術(shù)獲取該類型注解中的一些信息
@Documented:被該注解修飾的類可以使用 javadoc 工具生成文檔,這里就不演示了
Inherited:如果子類繼承了被 Inherited 修飾的注解,則子類也自動擁有父類中的注解
下面我們通過個例子來加深下理解,下面是 @Deprecated 注解的底層實現(xiàn)
/** * 表示可以被生成文檔 * 在程序運(yùn)行時也會被保留 * 可以使用在構(gòu)造器,屬性,方法,類或接口,包上等 */ @Documented @Retention(RetentionPolicy.RUNTIME) @Target(value={CONSTRUCTOR, FIELD, LOCAL_VARIABLE, METHOD, PACKAGE, PARAMETER, TYPE}) public @interface Deprecated { }三、反射注解
jdk1.5 在 java.lang.refelect 包下新增了 AnnotatedElement 接口,該接口中提供了一些用于反射注解的方法,如下
下面通過一個例子來解析注解
自定義 @MyAnno 注解
/*** @Target 約束該注解只能作用于類接口或枚舉上* @Retention 表示這是一個運(yùn)行時注解,可以通過反射技術(shù)獲取注解中的信息*/ @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) public @interface MyAnno {String username();int age() default 18; }Person 類,使用 @MyAnno 注解標(biāo)識
@MyAnno(username = "張三") public class Person { }MainDriver 測試類
public class MainDriver {public static void main(String[] args) {// 通過反射獲得 Person 類的 class 對象Class<Person> clazz = Person.class;if (clazz.isAnnotationPresent(MyAnno.class)) {// 通過 class 對象獲取 MyAnno 注解對象MyAnno anno = clazz.getAnnotation(MyAnno.class);// 獲取注解中的屬性值String username = anno.username();int age = anno.age();System.out.println(username + " " + age);} else {System.out.println("該類上沒有注解");}} }四、注解與反射的綜合應(yīng)用
這里我們模擬一下 Spring Data JPA 中有關(guān)注解的實現(xiàn),使用注解與反射技術(shù)拼接查詢的 SQL 語句
自定義 @Table 注解
@Target({ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) public @interface Table {String value(); }自定義 @Column 注解
@Target({ElementType.FIELD}) @Retention(RetentionPolicy.RUNTIME) public @interface Column {String value(); }與數(shù)據(jù)庫映射的實體 Student 類
/*** 當(dāng)注解中只有一個 value 屬性時,可以直接定義注解屬性值*/ @Table("student") public class Student {@Column("id")private int id;@Column("user_name")private String username;@Column("age")private int age;@Column("city")private String city;@Column("phone")private String phone;// 省略 get 與 set 方法 }注解解析 MainDriver 類
public class MainDriver {public static void main(String[] args) throws Exception {Student student1 = new Student();student1.setUsername("張三");student1.setAge(18);student1.setCity("hangzhou");String s1 = query(student1);System.out.println(s1);Student student2 = new Student();student2.setUsername("李四");student2.setPhone("12345678977");String s2 = query(student2);System.out.println(s2);}public static String query(Student student) throws Exception {StringBuilder sb = new StringBuilder();Class<?> clazz = student.getClass();boolean tableAnnoExits = clazz.isAnnotationPresent(Table.class);// 判斷 class 對象上是否有 @Table 注解if (!tableAnnoExits) {return null;}// 獲取 @Table 注解中的表名,拼接 SQlTable table = clazz.getAnnotation(Table.class);String tableName = table.value();sb.append("SELECT * FROM " + tableName + " WHERE 1 = 1");// 獲取 class 對象中的所有字段并遍歷Field[] fields = clazz.getDeclaredFields();for (Field field : fields) {boolean fieldAnnoExits = field.isAnnotationPresent(Column.class);// 判斷字段上是否含有 @Column 注解if (!fieldAnnoExits) {continue;}// 獲取注解中的字段名Column column = field.getAnnotation(Column.class);String columnName = column.value();// 通過 get() 方法獲取傳入的字段值String fieldName = field.getName();String getMethodName = "get" + fieldName.substring(0, 1).toUpperCase() + fieldName.substring(1);Method method = clazz.getMethod(getMethodName);Object fieldValue = method.invoke(student);if (fieldValue == null || (fieldValue instanceof Integer && (Integer)fieldValue == 0)) {continue;}// 接著拼接 SQL 語句sb.append(" AND ").append(columnName).append(" = ");if (fieldValue instanceof String) {sb.append("'").append(fieldValue).append("'"); } else if (fieldValue instanceof Integer) {sb.append(fieldValue);}}return sb.toString();} }執(zhí)行結(jié)果
GitHub 代碼地址,點我前往~
總結(jié)
- 上一篇: 守护宝是什么东西
- 下一篇: java美元兑换,(Java实现) 美元