1. 程式人生 > >Java反射&註解-筆記

Java反射&註解-筆記

Java反射偷懶小記

工作以來很少些部落格,在各位大佬的影響下決定還是記錄下自己工作的點點滴滴,以免自己以後找尋相關知識還是繼續百度。像今天早上媳婦兒提到他用java-wrapper部署spring-boot,一時半會兒我居然想不起來java-wrapper是什麼。想當初對wrapper熟悉得想左右手一樣。哎…… 痛改前非,從今天開始把有意義的事情都記錄下吧,不廢話了還是來談主題java的反射。 最近在做一個http介面時,用到一些發射和註解的東西。能方便的實現該功能。其中一個功能就是提交的客戶斷應該會提交叫N個欄位,但是在實際中他可能只會提交M個(M < N)那每次都需要取統計這個M以便後面能快速的生成報表等。個人想到的辦法有 1.直接將上報的欄位全部判斷一次,程式碼直接一個欄位一個欄位的取遍歷完成。 2.採用註解加反射的方式完成統計。相比方法1來說至少程式碼會好看些。沒有那麼複雜的圈複雜度。

java反射

談到java反射的列子,理論都很多,做過java專案的人基本都用到過反射。java的各類框架就更不用談了,基本上沒有反射這些框架都得回孃胎去。這裡就簡單說一下java反射裡面比較常用的東西,個人覺得比較實用,如果想了解比較深就不用看我這個了。

  • 核心類java.lang.Class 雖然java的反射相關的包都在java.lang.reflect包下面,但是鄙人認為反射還得從lang包下的Class類說起,因為Java類的結構包括的 靜態欄位,靜態方法,欄位,常量等都需要從這個Class上去獲取:

    Class clz = this.getClass();
    Field[] fields = clz.getDeclaredFields();//獲取到該類所有的欄位。包括非靜態的。
    Field[] fields1 = clz.getFields();//獲取到該類所有的靜態的欄位。

    可能很多人都會想java的開發者為什麼會這樣定義兩個方法。 個人理解是既然是類,那類本身屬性肯定是隻有靜態的啊。(畢竟靜態是類的,非靜態就是物件的了。純粹個人理解,也為了好記。)所以直接從在類裡面所有的申明時才可以獲取到非靜態的方法。

  • 如何能獲取到該類及父類所有的欄位 在很多情況下我們可能需要取獲取到父類的欄位進行操作。這個沒什麼好的辦法,直接一級一級的網上迴圈

    PushData pushData = new DayData();
        Class clz = pushData.getClass();
        while
    (clz != null) { //todo........... clz = clz.getSuperclass(); }
  • 如何獲取欄位上的值 在我的這個需求中其實沒有必要取獲取對應欄位的具體指,我只需要獲取到該欄位上是否有值就好了。後去方法很簡單

    Field field = fields[i]
    field.setAccessible(true);//一定要設定獲取許可權,沒許可權會報異常
    Object obj =   field.get() ;

    JAVA註解

    Java的註解也是一個很久遠的功能,從java誕生到現在依然是一個用得很多的功能,尤其現在為了減少各種XML,properties的配置,註解就成為了一個香餑餑。

  • 註解的級別 所謂註解的級別,個人理解就是註解在Java編寫到執行的過程中那些場景下可以被解讀。所以與之對應的編寫註解類的時候可指定註解類的級別,對應的註解標籤類為:Retention 可選的RetentionPolicy引數包括:

    1. SOURCE:註解將被編譯器丟棄
    2. CLASS:註解在class檔案中可用,但會被VM丟棄
    3. RUNTIME:VM將在執行期間保留註解,因此可以通過反射機制讀取註解的資訊。 好不好玩? 那猜一下這個Retention是哪個級別的註解.
  • 註解可以被用到哪裡 註解我們都用過,比較出名的就是 @Override 我們知道在重寫方法的時候會用到這個註解,並且用在方法上面。你拿去用到類上面你看看會怎麼樣,肯定會報錯。 這個之後你肯定能理解到註解其實是可以定義他可以放到哪裡了吧。 這類我們需要用到一個註解標籤@Target具體由那些地方可以放可以去看註解類java.lang.annotation.ElementType 例如我自定義的註解類:

package xx.yy.;
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 CheckProperty {
}

是不是很簡單,這裡我們把他定義到RUNTIME 應該很好理解,畢竟我們需要在虛擬機器執行時對主機進行解析嘛。

- 接下來我整體描述下我整體實現的這功能

實體物件

首先我定義一給基礎實體類命名為PushData 然後他

Created with Raphaël 2.1.2DayDataDayDataPushDataPushDataMinuteDataMinuteDataHourDataHourDataDayDataDayData繼承直繼承直繼承直

哈哈,畫不來類圖,先用這個代替吧,反正就是我有那麼幾個實體類DayData(天資料) /MinuteData(分鐘資料)/HourData(小時資料) 讓他們都繼承直一個根類PushData 因為小時資料和分鐘資料有部分有重疊,所以分鐘資料繼承直小時資料。

將自定義的欄位加到需要統計欄位上

 //出現時間
    @CheckProperty
    @JsonProperty("MAXTM")
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    private Date MAXTM;

上面的@JsonProperty("MAXTM")@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")是fastjson的註解可以將json弄到對應的欄位上,@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")就是對時間做一個格式化嘛。這個就不描述了。

Created with Raphaël 2.1.2開始 POST提價 邏輯處理 計算有效欄位入庫結束

統計有效欄位程式碼

/**
*統計上報有效欄位
*/
public int getCheckedValidCols() {
        int count = 0;
        Class clz = this.getClass();
        while (clz != null) {
            Field[] fields = clz.getDeclaredFields();
            for (Field field : fields) {
                if (checkedProperty(field)) {
                    try {
                        if (null != field.get(this)) {
                            count++;
                        }
                    } catch (Exception d) {
                        d.printStackTrace();
                    }
                }
            }
            clz = clz.getSuperclass();
        }

        return count;
    }

    private boolean checkedProperty(Field field) {
        CheckProperty checkProperty = field.getAnnotation(CheckProperty.class);
        if (checkProperty == null) {
            return false;
        }

        try {
            field.setAccessible(true);
            Object object = field.get(this);
            if (object == null) {
                return false;
            }
        } catch (IllegalAccessException e) {
            e.printStackTrace();
            return false;
        }
        return true;
    }

快速生成介面提交Body 樣例

採用fastjson產生json字串時,預設都回忽略掉空欄位。對於產生介面樣例麻煩了點。這個操作就為偷點懶。沒別的意思

public static void main(String[] args) {
        PushData pushData = new DayData();
        Class clz = pushData.getClass();
         System.out.println("{");
        while (clz != null) {
            Field[] fields = clz.getDeclaredFields();
            for (Field field : fields) {
                JsonProperty jsonProperty = field.getAnnotation(JsonProperty.class);
                if (jsonProperty != null) {
                    JsonFormat jsonFormat = field.getAnnotation(JsonFormat.class);
                    if (null == jsonFormat) {
                        String name = jsonProperty.value();
                        System.out.println("\"" + name + "\":\"1.0\",");
                    } else {
                        String name = jsonProperty.value();
                        System.out.println("\"" + name + "\":\"2018-09-18 13:50:23\",");
                    }

                }

            }
            clz = clz.getSuperclass();
        }
     System.out.println("}");
    }

產生的結果:

{
    "FType":"1.0",
    "VOL":"1.0",
    "SWS":"1.0",
    "SWD":"1.0",
    "WS":"1.0",
    "WD":"1.0",
    "BP":"1.0",
    "AT":"1.0",
    "HU":"1.0",
    "WT":"1.0",
    "SL":"1.0",
    "BG":"1.0",
    "BX":"1.0",
    "ZQ":"1.0",
    "YBG":"1.0",
    "YZQ":"1.0",
    "TENTHBG":"1.0",
    "TENTHZQ":"1.0",
    "ZBG":"1.0",
    "ZZQ":"1.0",
    "RN":"1.0",
    "VB":"1.0",
    "FS":"1.0",
    "WL":"1.0",
    "MAXWS":"1.0",
    "MAXWD":"1.0",
    "MAXTM":"2018-09-13 13:50:23",
    "GRTWS":"1.0",
    "GRTWD":"1.0",
    "GRTTM":"1.0",
    "GDC":"1.0",
    "DFSD":"1.0",
    "SWL":"1.0",
    "ZJS":"1.0",
    "WARNING":"1.0",
    "DT":"2018-09-13 13:50:23",//時間
    "CODE":"0002"//站點CODE
}

收工,第一次寫,確實寫得不怎麼樣啊,下次努力。