【iMooc】全面解析java註解
阿新 • • 發佈:2018-03-08
test sql語句 字符 con public insert OS 直接 變量 5.解析註解
在慕課上學習了一個關於java註解的課程,下面是筆記以及一些源碼。
Annotation——註解
1.JDK中的註解
JDK中包括下面三種註解:
@Override:標記註解(marker annotation),重寫,父類寫的方法,如果子類繼承了父類,就要重寫父類的方法。
@Deprecated:表示過時的語法加上這個註解之後,該方法上會出現一道刪除線
@SuppressWarning:忽略警告,壓制警告。如果某語句前面出現警告,加上這個註解,警告就會消失。
舉例如下:
父類 一個Person接口: @Deprecated表示該方法過時。
package com.ann.test; publicinterface Person { public String name(); public int age(); @Deprecated public void sing(); }
子類Child 集成父類,必須 重寫@Override父類的所有方法。
package com.ann.test; public class Child implements Person{ @Override public String name() { // TODO Auto-generated method stub returnnull; } @Override public int age() { // TODO Auto-generated method stub return 0; } @Override public void sing() { // TODO Auto-generated method stub } }
測試代碼: 測試代碼中調用了過時的sing()函數,產生警告。使用@SuppressWarnings註解 ,可消除警告。
package com.ann.test;public class Test { @SuppressWarnings("deprecation") public void sing() { Person p = new Child(); p.sing(); } }
2.常見第三方註解:
Spring:
- @Autowired:不用配置文件,可以自動生成Dao文件註入進去
- @Serice
- @Repository
Mybatis:
- @InsertProvider
- UpdataProvider
- @Options
3.註解分類:
按照運行機制:
- 編碼註解:只存在源碼中
- 編譯時註解:存在於源碼與.class中 如@override、@Deprecated、@SuppressWarning
- 運行時註解:運行時將成員變量自動註入(可能會影響運行邏輯)如Spring中的@AutoWired
按照來源:
- JDK註解
- 第三方註解(Spring等)
- 自定義註解
4.自定義註解
可新建一個Annotation,@interface表示註解。在自定義註解中,
- 成員變量必須是無參無異常的形式,可以設置使用default設置默認值
- 成員變量的類型:基本數據類型、String、class、Annotation、Enumeration
- 成員變量只有一個的時候,一般取名為value();使用的時候,可以直接賦值
- 可以沒有成員
package com.ann.test; import java.lang.annotation.Documented; import java.lang.annotation.ElementType; import java.lang.annotation.Inherited; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; @Target({ ElementType.METHOD, ElementType.TYPE }) @Retention(RetentionPolicy.RUNTIME) @Inherited @Documented public @interface Decription { String desc(); String author(); int age() default 18; }
@Target:表示註解作用域,關鍵字包括Constructor(構造函數)、Field(變量)、Local_veriable、method、package、parameter、tyoe(類,接口)
@Retention:生命周期:source、class、runtime
@Inherited:可以被子類繼承
@Documented:生成javadoc時包含註解信息
自定義註解的使用:
@<註解名>(<成員名1>=<value1>,.......)
如下:
package com.ann.test; @Decription(desc="I am class description", author = "YM") public class Child implements Person{ @Override @Decription(desc="I am method description", author = "YM", age = 18) public String name() { // TODO Auto-generated method stub return null; } @Override public int age() { // TODO Auto-generated method stub return 0; } @Override public void sing() { // TODO Auto-generated method stub } }
5.解析註解
- 首先使用加載器加載類
- 找到類上的註解
- 拿到註解實例
- 找到方法上的註解
另一種解析方法:以方法上的註解為例
- 遍歷所有的方法
- 拿出所有的註解
- 遍歷所有註解
package com.ann.test; import java.lang.annotation.Annotation; import java.lang.reflect.Method; public class ParseAnn { public static void main(String[] args) { try { //1.使用類加載器加載類 Class c=Class.forName("com.ann.test.Child"); //2找到類上的註解 boolean isExis = c.isAnnotationPresent(Decription.class); if(isExis){ //3.拿到註解實例 Decription d=(Decription) c.getAnnotation(Decription.class); System.out.println(d.desc()); } //4.找到方法上的註解 Method[] ms=c.getMethods(); for(Method m:ms){ boolean isMExis=m.isAnnotationPresent(Decription.class); if(isMExis){ Decription mds=(Decription)m.getAnnotation(Decription.class); System.out.println(mds.desc()); } } //另外一種解析方法 //1.遍歷所有方法 for(Method m:ms){ //2拿出所有註解 Annotation[] an=m.getAnnotations(); //3遍歷所有註解 for(Annotation a:an){ //如果a是我們自定義註解的實例 if(a instanceof Decription) { //將a強轉成Decription類 Decription d= (Decription)a; System.out.println(d.desc()); } } } } catch (ClassNotFoundException e) { // TODO Auto-generated catch block e.printStackTrace(); } } }
輸出:
I am class description I am method description I am method description
6.註解實戰:
需求:一張用戶表。自動的對每個字段或字段的組合條件進行檢索,拼接sql語句,並打印
Filter.class
package com.ann.dao; @Table("user") public class Filter { @Column("id") private int id; @Column("userName") private String userName; @Column("nikeName") private String nikeName; @Column("age") private int age; @Column("city") private String city; @Column("email") private String email; @Column("mobile") private String mobile; public int getId() { return id; } public void setId(int id) { this.id = id; } public String getUserName() { return userName; } public void setUserName(String userName) { this.userName = userName; } public String getNikeName() { return nikeName; } public void setNikeName(String nikeName) { this.nikeName = nikeName; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public String getCity() { return city; } public void setCity(String city) { this.city = city; } public String getEmail() { return email; } public void setEmail(String email) { this.email = email; } public String getMobile() { return mobile; } public void setMobile(String mobile) { this.mobile = mobile; } }
Table (自定義註解)作用域為TYPE表示類
package com.ann.dao; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; @Target({ ElementType.TYPE }) @Retention(RetentionPolicy.RUNTIME) public @interface Table { public String value(); }
Column (自定義註解)
package com.ann.dao; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; @Target({ ElementType.FIELD }) @Retention(RetentionPolicy.RUNTIME) public @interface Column { public String value(); }
Test :
package com.ann.dao; import java.lang.reflect.Field; import java.lang.reflect.Method; public class Test { // 1.首先考慮代碼怎麽與數據庫做映射 filter是與數據庫關系最緊密的類-轉到filter // 2需要考慮query方法如何實現 public static void main(String[] args) { Filter f1 = new Filter(); f1.setId(10);// 查詢id為10的用戶 Filter f2 = new Filter(); f2.setUserName("Tom");// 查詢用戶名為tom的用戶 f2.setAge(18); Filter f3 = new Filter(); f3.setEmail("[email protected],[email protected]"); String sql1 = query(f1); String sql2 = query(f2); String sql3 = query(f3); System.out.println("sql1:" + sql1); System.out.println("sql2:" + sql2); System.out.println("sql3:" + sql3); //寫一個filter可以應用到不同的表中 Filter2 filter2= new Filter2(); filter2.setAmount(10); filter2.setId(1); filter2.setName("技術"); System.out.println(query(filter2)); } private static String query(Object f) { // 首先用一個StringBuilder來存儲字符串表示sql語句 StringBuilder sb = new StringBuilder(); // 1獲取class Class c = f.getClass(); // 2.獲取table名 boolean isCExis = c.isAnnotationPresent(Table.class); if (!isCExis) { return null; } Table t = (Table) c.getAnnotation(Table.class); String tableName = t.value(); sb.append("select * from ").append(tableName).append(" where 1=1"); // 3.遍歷所有字段 Field[] field = c.getDeclaredFields(); for (Field fi : field) { // 4.處理每個字段對應的sql // 4.1拿到字段的名字 boolean isFExis = fi.isAnnotationPresent(Column.class); if (!isFExis) { continue; } Column col = fi.getAnnotation(Column.class); String columnName = col.value(); // 4.2拿到字段的值(反射) String fieldName = fi.getName();// 字段名 // 先拿到get方法的名字 String getMethodName = "get" + fieldName.substring(0, 1).toUpperCase() + fieldName.substring(1); Object fieldValue = null; try { Method getMethod = c.getMethod(getMethodName); fieldValue = getMethod.invoke(f); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } // 4.3拼接 if (fieldValue == null || (fieldValue instanceof Integer && (Integer) fieldValue == 0)) { continue; } sb.append(" and ").append(fieldName); if (fieldValue instanceof Integer) { sb.append(" = ").append(fieldValue); } else if (fieldValue instanceof String) { if (((String) fieldValue).contains(",")) {// 郵箱格式包含,表示有多種選擇 String[] string = ((String) fieldValue).split(","); sb.append(" in ("); for(String str:string){ sb.append("‘").append(str).append("‘").append(","); } sb.deleteCharAt(sb.length()-1); sb.append(")"); } else { sb.append(" = ‘").append(fieldValue).append("‘"); } } } return sb.toString(); } }
sql1:select * from user where 1=1 and id = 10 sql2:select * from user where 1=1 and userName = ‘Tom‘ and age = 18 sql3:select * from user where 1=1 and email in (‘[email protected]‘,‘[email protected]‘)
【iMooc】全面解析java註解