1. 程式人生 > >【iMooc】全面解析java註解

【iMooc】全面解析java註解

test sql語句 字符 con public insert OS 直接 變量

在慕課上學習了一個關於java註解的課程,下面是筆記以及一些源碼。

Annotation——註解

1.JDK中的註解

JDK中包括下面三種註解:

@Override:標記註解(marker annotation),重寫,父類寫的方法,如果子類繼承了父類,就要重寫父類的方法。

@Deprecated:表示過時的語法加上這個註解之後,該方法上會出現一道刪除線

@SuppressWarning:忽略警告,壓制警告。如果某語句前面出現警告,加上這個註解,警告就會消失。

舉例如下:

父類 一個Person接口: @Deprecated表示該方法過時。

package com.ann.test;

public
interface 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
        return
null; } @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表示註解。在自定義註解中,

  1. 成員變量必須是無參無異常的形式,可以設置使用default設置默認值
  2. 成員變量的類型:基本數據類型、String、class、Annotation、Enumeration
  3. 成員變量只有一個的時候,一般取名為value();使用的時候,可以直接賦值
  4. 可以沒有成員
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.解析註解

  1. 首先使用加載器加載類
  2. 找到類上的註解
  3. 拿到註解實例
  4. 找到方法上的註解

另一種解析方法:以方法上的註解為例

  1. 遍歷所有的方法
  2. 拿出所有的註解
  3. 遍歷所有註解


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註解