1. 程式人生 > >Java註解詳解,自定義註解,利用反射解析註解

Java註解詳解,自定義註解,利用反射解析註解

概要

這篇文章將會帶領你瞭解Java註解,註解的使用,註解的解析,利用反射解析執行時註解,相信有一定Java基礎的小夥伴一定會接觸大量的註解,Spring , Hibernate , MyBatis等著名的框架也有很多關於註解方面的應用,對於註解的使用小夥伴們應該一點都不陌生,那麼如何自定義註解呢?學會自定義註解有什麼好處呢?
下面就隨筆者進入註解的世界

註解的作用

很多小夥伴在學習註解之前,都不知道學習註解到底可以用來幹什麼,可以給自身帶來什麼好處,那麼在這裡,筆者描述學習註解的幾點好處

  • 用過Hibernate的小夥伴,應該使用過Hibernate的配置檔案來描述ORM(資料庫關係對映),Hibernate實現此功能除了寫配置檔案之外,當然還包含註解,那麼第一個好處就是,註解可以替代配置檔案完成對某些功能的描述,減少程式配置
  • 在沒有配置檔案的情況下,我們去觀察程式碼,並不需要同時開啟兩個檔案來觀察這個欄位到底對應資料庫的哪個列,減少了程式繁瑣性,使得程式碼更加清晰易懂
  • 目前市面上流行的框架基本上都包含了註解配置,那麼針對於開源專案,我們在閱讀專案程式碼時,不懂註解如何實現,真的是舉步難堅,所以,學習註解也可以加強我們對開源專案原始碼的解讀
  • 最重要的一點,會使用註解和會自定義註解完全是兩碼事,我的意思是,讓別人可以高看你一眼(zhuang bi)

瞭解註解

註解是Java1.5,JDK5.0引用的技術,與類,介面,列舉處於同一層次 。它可以宣告在包、類、欄位、方法、區域性變數、方法引數等的前面,用來對這些元素進行說明,註釋 。

在Java中,自帶了三種註解,這三種註解存在於java.lang包中,首先我們講一講這些註解

  • Override——它的作用是對覆蓋超類中方法的方法進行標記,如果被標記的類並沒有實際覆蓋超類,則編譯器會發出錯誤警告。
    很常見的一個註解,瞭解JavaOOP的小夥伴這個註解應該較為常用,告訴編譯器,我這個方法是重寫了父類方法,當然如果你的方法並沒有實際重寫父類方法時,那麼編譯器就會顯示警告資訊
  • Deprecated——它的作用是對不應該再使用的方法添加註解,當程式設計人員使用這些方法時,將會在編譯時顯示提示資訊
    當一個方法名或者類名上面此註解之後,編譯器會認為這個方法屬於過期方法,明顯的區別在於類名或者方法名上會畫一道刪除線,標識過期方法不影響方法的繼續使用
  • SuppressWarnings——這個僅僅是告訴編譯器忽略特定的警告資訊,例如在泛型中使用原生資料型別
    例如我們在使用一些以Deprecated註解的方法時,編譯器會提出黃線警告,那麼只要在使用的地方加上@SuppressWarnings(“deprecation”)就可以使編譯器忽略這個警告
    此註釋常用的引數值有 : deprecation(忽略使用過時類或者方法),unchecked(忽略執行了未檢查裝換時警告) , fallthrough(忽略switch直接指向到下一個case塊沒有break警告),path(忽略類路徑,原始檔路徑中有不存在路徑時警告),serial(忽略可序列化類中沒有serialVersionUID時的警告),finally(任何finally不能正常執行時的警告),all(以上所有)

自定義註解須知

首先,自定義註解我們必須瞭解四個元註解,什麼是元註解?元註解指作用於註解之上的元資料或者元資訊,簡單通俗的講,元註解就是註解的註解 .

  • Documented——指明擁有這個註解的元素可以被javadoc此類的工具文件化。這種型別應該用於註解那些影響客戶使用帶註釋的元素宣告的型別。如果一種宣告使用Documented進行註解,這種型別的註解被作為被標註的程式成員的公共API 。
  • Inherited——指明該註解型別被自動繼承。如果使用者在當前類中查詢這個元註解型別並且當前類的宣告中不包含這個元註解型別,那麼也將自動查詢當前類的父類是否存在Inherited元註解,這個動作將被重複執行知道這個標註型別被找到,或者是查詢到頂層的父類。
  • Retention——指明在什麼級別顯示此註解
  • Target——指明該型別的註解可以註解的程式元素的範圍

Documented與Inherited是典型的標識性註解,也就是說在註解內部並沒有成員變數,沒有成員變數的註解稱為標識註解
Target主要的引數型別包括以下幾種

  • ElementType.TYPE 用於類,介面,列舉但不能是註解
  • ElementType.FIELD 作用於欄位,包含列舉值
  • ElementType.METHOD 作用於方法,不包含構造方法
  • ElementType.PARAMETER 作用於方法的引數
  • ElementType.CONSTRUCTOR 作用於構造方法
  • ElementType.LOCAL_VERIABLE 作用於本地變數或者catch語句
  • ElementType.ANNOTATION_TYPE 作用於註解
  • ElementType.PACKAGE 作用於包

Retention主要的引數型別包括以下幾種

  • RetentionPolicy.SOURCE 註解存在於原始碼中,編譯時會被拋棄
  • RetentionPolicy.CLASS 註解會被編譯到class檔案中,但是JVM會忽略
  • RetentionPolicy.RUNTIME JVM會讀取註解,同時會儲存到class檔案中

自定義註解

首先,我們來看一段自定義註解實現的程式碼

@Documented
@Inherited
//該註解可以作用於方法,類與介面
@Target({ElementType.METHOD,ElementType.TYPE})
//JVM會讀取註解,所以利用反射可以獲得註解
@Retention(RetentionPolicy.RUNTIME)
public @interface TestAnnotation {
    //定義成員變數
    //成員變數可以通過default指定預設值
    //如果成員變數不指定預設值的情況下
    //我們在引用介面時則必須給沒有預設值的成員變數賦值
    String name() ; 
    int age() default 18 ;
}

@interface 用於定義註解介面,介面中只能定義成員變數,且定義的成員變數必須以()結尾,可以使用default關鍵字為成員變數指定預設值,如果不為成員變數指定預設值的情況,則必須在引用註解時,對沒有預設值的成員變數進行賦值操作

註解的使用規則:

//@註解名(變數1=變數1值,變數2=變數2值,...)
//如果註解中擁有陣列型別,假設是String型別,那麼賦值方式可以如下
//@註解名(String陣列名稱={"tset1","test2","test3"})

@TestAnnotation(name="Taro")

//因為我們註解中的age()是擁有預設值的,所以這邊可以不為age()賦值
//如果我們的註解中只有一個成員變數,且成員變數的名稱為value()
//那麼可以使用如下賦值方式
//@註解名(屬性值)
//如果我們的註解中沒有成員變數,那麼此時的註解被稱為標識註解

註解中可以定義的資料型別是受到限制的,除了基本型別之外,String,Enums,Annotation,Class還有這些型別的陣列
如何使用我們剛剛定義的註解呢?剛剛的註解我們聲明瞭是針對方法和類或者介面生效,那麼我們來看看使用方法

@TestAnnotation(name="I'm class annotation")
public class Test {

    @TestAnnotation(name="I'm method annotation")
    public static void showAnnotation(){

    }

}

怎麼樣,是不是很easy呢?

解析註解

主要使用Java的反射原理實現對註解的解析,不太懂反射的小夥伴通過筆者的註釋看起來也不會很難

PS :下一篇博文是對Java反射的詳解

public static void main(String[] args) {
    //解析註解
    //獲得我們需要解析註解的類
    Class<Test> clz = Test.class;

    //解析Class
    //由於我們的註解是可以給類使用的,所以首先判斷類上面有沒有我們的註解
    //判斷類上面是否有註解
    boolean clzHasAnnotation = clz.isAnnotationPresent(TestAnnotation.class);
    if(clzHasAnnotation){
        //類存在我們定義的註解
        //獲得註解
        TestAnnotation clzAnnotation = clz.getAnnotation(TestAnnotation.class);
        //輸出註解在類上的屬性
        System.out.println("name="+clzAnnotation.name()+"\tage="+clzAnnotation.age());
    }

    //解析Method
    //兩種解析方法上的註解方式
    //獲得類中所有方法
    Method[] methods = clz.getMethods();
    //第一種解析方法
    for(Method m : methods){
        //獲得方法中是否含有我們的註解
        boolean methodHasAnnotation = m.isAnnotationPresent(TestAnnotation.class);
        if(methodHasAnnotation){
            //註解存在
            //獲得註解
            TestAnnotation methodAnnotation = m.getAnnotation(TestAnnotation.class);

            System.out.println("name="+methodAnnotation.name()+"\tage="+methodAnnotation.age());
        }
    }
    //第二種解析方式
    for(Method m : methods){
        //獲得方法上所有註解
        Annotation[] annotations = m.getAnnotations();
        //迴圈註解
        for(Annotation a : annotations){
            //如果是我們自定義的註解
            if(a instanceof TestAnnotation){
                //輸出屬性,需要強制裝換型別
                System.out.println("name="+((TestAnnotation)a).name()+"\tage="+((TestAnnotation)a).age());
            }
        }
    }

}

最後得出結果,因為我們使用了兩種解析Method註解的方式,所以最終會得到兩個Method上面的字串

結果

好了,這篇博文就到這裡,希望會幫到小夥伴們

相關推薦

java註解定義註解

本文首先介紹了註解的基本概念和JDK內建的標準註解,然後介紹瞭如何自定義註解,最後給出了自定義註解的例子。 一、註解的基本概念 Java 註解就像修飾符一樣,可以用於從java程式碼中抽取文件、跟蹤程式碼中的依賴性或者在編譯時做檢查。註解可以被應用在包、類、

Java註解定義註解利用反射解析註解

概要 這篇文章將會帶領你瞭解Java註解,註解的使用,註解的解析,利用反射解析執行時註解,相信有一定Java基礎的小夥伴一定會接觸大量的註解,Spring , Hibernate , MyBatis等著名的框架也有很多關於註解方面的應用,對於註解的使用小夥伴們

spark三種清理資料的方式:UDF定義函式spark.sql;Python中的zip()與*zip()函式//及python中的*args和**kwargs

(1)UDF的方式清理資料 import sys reload(sys) sys.setdefaultencoding('utf8') import re import json from pyspark.sql import SparkSession

Spring Boot 配置檔案定義屬性、隨機數、多環境配置等

相信很多人選擇Spring Boot主要是考慮到它既能兼顧Spring的強大功能,還能實現快速開發的便捷。我們在Spring Boot使用過程中,最直觀的感受就是沒有了原來自己整合Spring應用時繁多的XML配置內容,替代它的是在pom.xml中引入模組化的Starter POMs,其中各個模組都有自己的預

Service 服務定義服務模板

文章目錄 1、服務簡介 2、服務的生命週期 1) Service 的 啟動 停止 2)、服務的生命週期的方法 3、使用startService 啟動後服務

SpringBoot-配置檔案定義配置檔案

今天我們一起來學習一下如何自定義配置檔案,在這之前我們可能會把配置項寫在application.properties或者application.yml中。這是springboot預設讀取的配置檔案,但是

OpenLayers官方示例定義多邊形樣式(Custom Polygon Styles)

目錄 一、示例簡介 二、程式碼詳解 一、示例簡介     這個示例演示怎樣為多邊形要素建立自定義的樣式。     在這個示例中,將為多邊形建立兩種不同的樣式: 第一個樣式是多邊形的整體樣式 第二個樣式是為多邊形的各個頂點

許可權驗證程式碼定義許可權驗證類

一、許可權認證原始碼詳解 1、進入dispatch 2、initial中self.check_permissions(request)進行許可權驗證 3、進入check_permissions for permission in self.get_permissions(): 4、

Log4J日誌配置定義log4j日誌級別及輸出日誌到不同檔案實現方法

package com.jo.work.log4j; import java.util.Enumeration; import org.apache.log4j.Appender; import org.apache.log4j.FileAppender; import org.apache.log4j.

Andoid定義View的OnMeasure定義屬性

一,OnMeasure詳解 Android開發中偶爾會用到自定義View,一般情況下,自定義View都需要繼承View類的onMeasure方法,那麼,為什麼要繼承onMeasure()函式呢?什麼情況下要繼承onMeasure()?系統預設的onMeasure()函式行為

【系統學習SpringBoot】再遇Spring Data JPA之JPA應用定義查詢及複雜查詢)

在此,對Spring Data Jpa做詳細的筆記(使用層面的,原理層日後再說哈哈。) 一、Spring Data JPA設定建立方式: 建立方式一共分為四種: #配置資料庫,使用SpringJPA spring: datasource:

Android定義鍵盤定義輸入法簡介

概述 Android中有兩個系統類是用來實現鍵盤的,分別是Keyboard和KeyboardView。 Keyboard有個內部類Key,用於記錄每個鍵的資訊,如code、width、height等。而KeyBorad則持有一個List用於儲存所有Key,並

spring定義屬性編輯器

Spring DI注入的時候可以把普通屬性注入進來,但是像Date型別的就無法被識別。這時可以通過Spring的屬性編輯器把配置檔案中的字串轉化成相應的物件進行注入。 Spring有自帶的屬性編輯器,我們也可以寫自定義的屬性編輯器 自定義屬性編輯器: 繼承java.

CentOS7安裝定義安裝)

本文基於vmware workstations進行CentOS7安裝過程展示,關於vmware workstations安裝配置本人這裡不再介紹,基本過程相當於windows下安裝個軟體而已。 1、開啟vmware workstations,檔案->新建虛擬機器,出現如下介面,選擇“自定義(高階)”選項

Android-Handler機制定義Handler

之前研究過Android的Handler機制,但是一直沒有機會自己實現一次。最近又看到這個Handler機制,於是決定自己實現以下這個Handler機制。 首先,簡單介紹以下Handler機制。 Handler機制在Android中通常用來更新UI:子執行緒

安卓behavior3--定義behavior

一.前言 官方定義: A Behavior implements one or more interactions that a user can take on a child view. These interactions may include dr

資料庫連線池原理定義連線池實現

實現原理資料庫連線池在初始化時將建立一定數量的資料庫連線放到連線池中,這些資料庫連線的數量是由最小資料庫連線數制約。無論這些資料庫連線是否被使用,連線池都將一直保證至少擁有這麼多的連線數量。連線池的最大資料庫連線數量限定了這個連線池能佔有的最大連線數,當應用程式向連線池請求的連

MapReduce中的combiner類定義combiner類(轉)

一、Combiner的出現背景 1.1 回顧Map階段五大步驟   在第四篇博文《初識MapReduce》中,我們認識了MapReduce的八大步湊,其中在Map階段總共五個步驟,如下圖所示:   其中,step1.5是一個可選步驟,它就是我們今天需要了解的 M

django 的模板語言template 定義過濾器定義標簽模板繼承

test block src view -- back def 其他 init 後端views文件傳來的字符串和對象,到前端頁面後需要進行渲染, {{ 變量 }}{{ 變量| filter:參數 }}filter可以有很多函數 {#對後端傳來的數據進行渲染,add 就是過濾

實現類似微信表情包橫向滾動翻頁的功能運用UICollectionView定義UICollectionViewFlowLayoutcell左右排版 支持多組Cell實現。

hang sig idt 滾動翻頁 功能 details assign 實現類 targe 結合:https://blog.csdn.net/qiuhaozhou/article/details/54582741 下面是我所要的樣式的實現的代碼: .h文件如下: #i