日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程语言 > java >内容正文

java

框架基础:深入理解Java注解类型(@Annotation)

發(fā)布時(shí)間:2023/12/6 java 56 豆豆
生活随笔 收集整理的這篇文章主要介紹了 框架基础:深入理解Java注解类型(@Annotation) 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

注解的概念

注解的官方定義

首先看看官方對(duì)注解的描述:

An annotation is a form of metadata, that can be added to Java source code. Classes, methods, variables, parameters and packages may be annotated. Annotations have no direct effect on the operation of the code they annotate.

翻譯:

注解是一種能被添加到j(luò)ava代碼中的元數(shù)據(jù),類、方法、變量、參數(shù)和包都可以用注解來(lái)修飾。注解對(duì)于它所修飾的代碼并沒有直接的影響。

通過官方描述得出以下結(jié)論:

注解是一種元數(shù)據(jù)形式。即注解是屬于java的一種數(shù)據(jù)類型,和類、接口、數(shù)組、枚舉類似。
注解用來(lái)修飾,類、方法、變量、參數(shù)、包。
注解不會(huì)對(duì)所修飾的代碼產(chǎn)生直接的影響。

注解的使用范圍

繼續(xù)看看官方對(duì)它的使用范圍的描述:

Annotations have a number of uses, among them:Information for the complier - Annotations can be used by the compiler to detect errors or suppress warnings.Compiler-time and deployment-time processing - Software tools can process annotation information to generate code, XML files, and so forth.Runtime processing - Some annotations are available to be examined at runtime.

翻譯:

注解又許多用法,其中有:為編譯器提供信息 - 注解能被編譯器檢測(cè)到錯(cuò)誤或抑制警告。編譯時(shí)和部署時(shí)的處理 - 軟件工具能處理注解信息從而生成代碼,XML文件等等。運(yùn)行時(shí)的處理 - 有些注解在運(yùn)行時(shí)能被檢測(cè)到。

##2 如何自定義注解
基于上一節(jié),已對(duì)注解有了一個(gè)基本的認(rèn)識(shí):注解其實(shí)就是一種標(biāo)記,可以在程序代碼中的關(guān)鍵節(jié)點(diǎn)(類、方法、變量、參數(shù)、包)上打上這些標(biāo)記,然后程序在編譯時(shí)或運(yùn)行時(shí)可以檢測(cè)到這些標(biāo)記從而執(zhí)行一些特殊操作。因此可以得出自定義注解使用的基本流程:

第一步,定義注解——相當(dāng)于定義標(biāo)記;
第二步,配置注解——把標(biāo)記打在需要用到的程序代碼中;
第三步,解析注解——在編譯期或運(yùn)行時(shí)檢測(cè)到標(biāo)記,并進(jìn)行特殊操作。

基本語(yǔ)法

注解類型的聲明部分:

注解在Java中,與類、接口、枚舉類似,因此其聲明語(yǔ)法基本一致,只是所使用的關(guān)鍵字有所不同@interface。在底層實(shí)現(xiàn)上,所有定義的注解都會(huì)自動(dòng)繼承java.lang.annotation.Annotation接口。

public @interface CherryAnnotation {
}

注解類型的實(shí)現(xiàn)部分:

根據(jù)我們?cè)谧远x類的經(jīng)驗(yàn),在類的實(shí)現(xiàn)部分無(wú)非就是書寫構(gòu)造、屬性或方法。但是,在自定義注解中,其實(shí)現(xiàn)部分只能定義一個(gè)東西:注解類型元素(annotation type element)。咱們來(lái)看看其語(yǔ)法:

public @interface CherryAnnotation {public String name();int age() default 18;int[] array(); }

定義注解類型元素時(shí)需要注意如下幾點(diǎn):

  • 訪問修飾符必須為public,不寫默認(rèn)為public;

  • 該元素的類型只能是基本數(shù)據(jù)類型、String、Class、枚舉類型、注解類型(體現(xiàn)了注解的嵌套效果)以及上述類型的一位數(shù)組;

  • 該元素的名稱一般定義為名詞,如果注解中只有一個(gè)元素,請(qǐng)把名字起為value(后面使用會(huì)帶來(lái)便利操作);

  • ()不是定義方法參數(shù)的地方,也不能在括號(hào)中定義任何參數(shù),僅僅只是一個(gè)特殊的語(yǔ)法;

  • default代表默認(rèn)值,值必須和第2點(diǎn)定義的類型一致;

  • 如果沒有默認(rèn)值,代表后續(xù)使用注解時(shí)必須給該類型元素賦值。

  • 常用的元注解

    一個(gè)最最基本的注解定義就只包括了上面的兩部分內(nèi)容:1、注解的名字;2、注解包含的類型元素。但是,我們?cè)谑褂肑DK自帶注解的時(shí)候發(fā)現(xiàn),有些注解只能寫在方法上面(比如@Override);有些卻可以寫在類的上面(比如@Deprecated)。當(dāng)然除此以外還有很多細(xì)節(jié)性的定義,那么這些定義該如何做呢?接下來(lái)就該元注解出場(chǎng)了!
    元注解:專門修飾注解的注解。它們都是為了更好的設(shè)計(jì)自定義注解的細(xì)節(jié)而專門設(shè)計(jì)的。我們?yōu)榇蠹乙粋€(gè)個(gè)來(lái)做介紹。

    @Target

    @Target注解,是專門用來(lái)限定某個(gè)自定義注解能夠被應(yīng)用在哪些Java元素上面的。它使用一個(gè)枚舉類型定義如下:

    public enum ElementType {/** 類,接口(包括注解類型)或枚舉的聲明 */TYPE,/** 屬性的聲明 */FIELD,/** 方法的聲明 */METHOD,/** 方法形式參數(shù)聲明 */PARAMETER,/** 構(gòu)造方法的聲明 */CONSTRUCTOR,/** 局部變量聲明 */LOCAL_VARIABLE,/** 注解類型聲明 */ANNOTATION_TYPE,/** 包的聲明 */PACKAGE }

    ?

    //@CherryAnnotation被限定只能使用在類、接口或方法上面 @Target(value = {ElementType.TYPE,ElementType.METHOD}) public @interface CherryAnnotation {String name();int age() default 18;int[] array(); }

    @Retention

    @Retention注解,翻譯為持久力、保持力。即用來(lái)修飾自定義注解的生命力。
    注解的生命周期有三個(gè)階段:1、Java源文件階段;2、編譯到class文件階段;3、運(yùn)行期階段。同樣使用了RetentionPolicy枚舉類型定義了三個(gè)階段:

    public enum RetentionPolicy {/*** Annotations are to be discarded by the compiler.* (注解將被編譯器忽略掉)*/SOURCE,/*** Annotations are to be recorded in the class file by the compiler* but need not be retained by the VM at run time. This is the default* behavior.* (注解將被編譯器記錄在class文件中,但在運(yùn)行時(shí)不會(huì)被虛擬機(jī)保留,這是一個(gè)默認(rèn)的行為)*/CLASS,/*** Annotations are to be recorded in the class file by the compiler and* retained by the VM at run time, so they may be read reflectively.* (注解將被編譯器記錄在class文件中,而且在運(yùn)行時(shí)會(huì)被虛擬機(jī)保留,因此它們能通過反射被讀取到)* @see java.lang.reflect.AnnotatedElement*/RUNTIME }

    我們?cè)僭斀庖幌?#xff1a;

  • 如果一個(gè)注解被定義為RetentionPolicy.SOURCE,則它將被限定在Java源文件中,那么這個(gè)注解即不會(huì)參與編譯也不會(huì)在運(yùn)行期起任何作用,這個(gè)注解就和一個(gè)注釋是一樣的效果,只能被閱讀Java文件的人看到;

  • 如果一個(gè)注解被定義為RetentionPolicy.CLASS,則它將被編譯到Class文件中,那么編譯器可以在編譯時(shí)根據(jù)注解做一些處理動(dòng)作,但是運(yùn)行時(shí)JVM(Java虛擬機(jī))會(huì)忽略它,我們?cè)谶\(yùn)行期也不能讀取到;

  • 如果一個(gè)注解被定義為RetentionPolicy.RUNTIME,那么這個(gè)注解可以在運(yùn)行期的加載階段被加載到Class對(duì)象中。那么在程序運(yùn)行階段,我們可以通過反射得到這個(gè)注解,并通過判斷是否有這個(gè)注解或這個(gè)注解中屬性的值,從而執(zhí)行不同的程序代碼段。我們實(shí)際開發(fā)中的自定義注解幾乎都是使用的RetentionPolicy.RUNTIME;

  • 自定義注解

    在具體的Java類上使用注解

    @Retention(RetentionPolicy.RUNTIME) @Target(value = {ElementType.METHOD}) @Documented public @interface CherryAnnotation {String name();int age() default 18;int[] score(); }

    ?

    public class Student {@CherryAnnotation(name = "cherry-peng",age = 23,score = {99,66,77})public void study(int times){for(int i = 0; i < times; i++){System.out.println("Good Good Study, Day Day Up!");}} }

    簡(jiǎn)單分析下:

  • CherryAnnotation的@Target定義為ElementType.METHOD,那么它書寫的位置應(yīng)該在方法定義的上方,即:public void study(int times)之上;

  • 由于我們?cè)贑herryAnnotation中定義的有注解類型元素,而且有些元素是沒有默認(rèn)值的,這要求我們?cè)谑褂玫臅r(shí)候必須在標(biāo)記名后面打上(),并且在()內(nèi)以“元素名=元素值“的形式挨個(gè)填上所有沒有默認(rèn)值的注解類型元素(有默認(rèn)值的也可以填上重新賦值),中間用“,”號(hào)分割;

  • 注解與反射機(jī)制

    為了運(yùn)行時(shí)能準(zhǔn)確獲取到注解的相關(guān)信息,Java在java.lang.reflect 反射包下新增了AnnotatedElement接口,它主要用于表示目前正在 VM 中運(yùn)行的程序中已使用注解的元素,通過該接口提供的方法可以利用反射技術(shù)地讀取注解的信息,如反射包的Constructor類、Field類、Method類、Package類和Class類都實(shí)現(xiàn)了AnnotatedElement接口,它簡(jiǎn)要含義如下:

    Class:類的Class對(duì)象定義  ?
    Constructor:代表類的構(gòu)造器定義  ?
    Field:代表類的成員變量定義?
    Method:代表類的方法定義  ?
    Package:代表類的包定義

    下面是AnnotatedElement中相關(guān)的API方法,以上5個(gè)類都實(shí)現(xiàn)以下的方法

    ?返回值?方法名稱?說(shuō)明
    ?<A extends Annotation>?getAnnotation(Class<A> annotationClass)?該元素如果存在指定類型的注解,則返回這些注解,否則返回 null。
    ?Annotation[]?getAnnotations()?返回此元素上存在的所有注解,包括從父類繼承的
    ?boolean?isAnnotationPresent(Class<? extends Annotation> annotationClass)?如果指定類型的注解存在于此元素上,則返回 true,否則返回 false。
    ?Annotation[]?getDeclaredAnnotations()?返回直接存在于此元素上的所有注解,注意,不包括父類的注解,調(diào)用者可以隨意修改返回的數(shù)組;這不會(huì)對(duì)其他調(diào)用者返回的數(shù)組產(chǎn)生任何影響,沒有則返回長(zhǎng)度為0的數(shù)組

    ?

    簡(jiǎn)單案例演示如下:

    @Documented @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) public @interface DocumentA { }

    ?

    package com.zejian.annotationdemo;import java.lang.annotation.Annotation; import java.util.Arrays;@DocumentA class A{}//繼承了A類 @DocumentB public class DocumentDemo extends A{public static void main(String... args){Class<?> clazz = DocumentDemo.class;//根據(jù)指定注解類型獲取該注解DocumentA documentA=clazz.getAnnotation(DocumentA.class);System.out.println("A:"+documentA);//獲取該元素上的所有注解,包含從父類繼承Annotation[] an= clazz.getAnnotations();System.out.println("an:"+ Arrays.toString(an));//獲取該元素上的所有注解,但不包含繼承!Annotation[] an2=clazz.getDeclaredAnnotations();System.out.println("an2:"+ Arrays.toString(an2));//判斷注解DocumentA是否在該元素上boolean b=clazz.isAnnotationPresent(DocumentA.class);System.out.println("b:"+b);} }

    執(zhí)行結(jié)果:

    A:@com.zejian.annotationdemo.DocumentA() an:[@com.zejian.annotationdemo.DocumentA(), @com.zejian.annotationdemo.DocumentB()] an2:@com.zejian.annotationdemo.DocumentB() b:true

    通過反射獲取上面我們自定義注解

    public class TestAnnotation {public static void main(String[] args){try {//獲取Student的Class對(duì)象Class stuClass = Class.forName("pojos.Student");//說(shuō)明一下,這里形參不能寫成Integer.class,應(yīng)寫為int.classMethod stuMethod = stuClass.getMethod("study",int.class);if(stuMethod.isAnnotationPresent(CherryAnnotation.class)){System.out.println("Student類上配置了CherryAnnotation注解!");//獲取該元素上指定類型的注解CherryAnnotation cherryAnnotation = stuMethod.getAnnotation(CherryAnnotation.class);System.out.println("name: " + cherryAnnotation.name() + ", age: " + cherryAnnotation.age()+ ", score: " + cherryAnnotation.score()[0]);}else{System.out.println("Student類上沒有配置CherryAnnotation注解!");}} catch (ClassNotFoundException e) {e.printStackTrace();} catch (NoSuchMethodException e) {e.printStackTrace();}} }

    運(yùn)行時(shí)注解處理器

    了解完注解與反射的相關(guān)API后,現(xiàn)在通過一個(gè)實(shí)例(該例子是博主改編自《Tinking in Java》)來(lái)演示利用運(yùn)行時(shí)注解來(lái)組裝數(shù)據(jù)庫(kù)SQL的構(gòu)建語(yǔ)句的過程

    /*** Created by ChenHao on 2019/6/14.* 表注解*/ @Target(ElementType.TYPE)//只能應(yīng)用于類上 @Retention(RetentionPolicy.RUNTIME)//保存到運(yùn)行時(shí) public @interface DBTable {String name() default ""; }/*** Created by ChenHao on 2019/6/14.* 注解Integer類型的字段*/ @Target(ElementType.FIELD) @Retention(RetentionPolicy.RUNTIME) public @interface SQLInteger {//該字段對(duì)應(yīng)數(shù)據(jù)庫(kù)表列名String name() default "";//嵌套注解Constraints constraint() default @Constraints; }/*** Created by ChenHao on 2019/6/14.* 注解String類型的字段*/ @Target(ElementType.FIELD) @Retention(RetentionPolicy.RUNTIME) public @interface SQLString {//對(duì)應(yīng)數(shù)據(jù)庫(kù)表的列名String name() default "";//列類型分配的長(zhǎng)度,如varchar(30)的30int value() default 0;Constraints constraint() default @Constraints; }/*** Created by ChenHao on 2019/6/14.* 約束注解*/@Target(ElementType.FIELD)//只能應(yīng)用在字段上 @Retention(RetentionPolicy.RUNTIME) public @interface Constraints {//判斷是否作為主鍵約束boolean primaryKey() default false;//判斷是否允許為nullboolean allowNull() default false;//判斷是否唯一boolean unique() default false; }/*** Created by ChenHao on 2019/6/14.* 數(shù)據(jù)庫(kù)表Member對(duì)應(yīng)實(shí)例類bean*/ @DBTable(name = "MEMBER") public class Member {//主鍵ID@SQLString(name = "ID",value = 50, constraint = @Constraints(primaryKey = true))private String id;@SQLString(name = "NAME" , value = 30)private String name;@SQLInteger(name = "AGE")private int age;@SQLString(name = "DESCRIPTION" ,value = 150 , constraint = @Constraints(allowNull = true))private String description;//個(gè)人描述//省略set get..... }

    上述定義4個(gè)注解,分別是@DBTable(用于類上)、@Constraints(用于字段上)、 @SQLString(用于字段上)、@SQLString(用于字段上)并在Member類中使用這些注解,這些注解的作用的是用于幫助注解處理器生成創(chuàng)建數(shù)據(jù)庫(kù)表MEMBER的構(gòu)建語(yǔ)句,在這里有點(diǎn)需要注意的是,我們使用了嵌套注解@Constraints,該注解主要用于判斷字段是否為null或者字段是否唯一。必須清楚認(rèn)識(shí)到上述提供的注解生命周期必須為@Retention(RetentionPolicy.RUNTIME),即運(yùn)行時(shí),這樣才可以使用反射機(jī)制獲取其信息。有了上述注解和使用,剩余的就是編寫上述的注解處理器了,前面我們聊了很多注解,其處理器要么是Java自身已提供、要么是框架已提供的,我們自己都沒有涉及到注解處理器的編寫,但上述定義處理SQL的注解,其處理器必須由我們自己編寫了,如下

    package com.chenHao.annotationdemo; import java.lang.annotation.Annotation; import java.lang.reflect.Field; import java.util.ArrayList; import java.util.List;/*** Created by chenhao on 2019/6/14.* 運(yùn)行時(shí)注解處理器,構(gòu)造表創(chuàng)建語(yǔ)句*/ public class TableCreator {public static String createTableSql(String className) throws ClassNotFoundException {Class<?> cl = Class.forName(className);DBTable dbTable = cl.getAnnotation(DBTable.class);//如果沒有表注解,直接返回if(dbTable == null) {System.out.println("No DBTable annotations in class " + className);return null;}String tableName = dbTable.name();// If the name is empty, use the Class name:if(tableName.length() < 1)tableName = cl.getName().toUpperCase();List<String> columnDefs = new ArrayList<String>();//通過Class類API獲取到所有成員字段for(Field field : cl.getDeclaredFields()) {String columnName = null;//獲取字段上的注解Annotation[] anns = field.getDeclaredAnnotations();if(anns.length < 1)continue; // Not a db table column//判斷注解類型if(anns[0] instanceof SQLInteger) {SQLInteger sInt = (SQLInteger) anns[0];//獲取字段對(duì)應(yīng)列名稱,如果沒有就是使用字段名稱替代if(sInt.name().length() < 1)columnName = field.getName().toUpperCase();elsecolumnName = sInt.name();//構(gòu)建語(yǔ)句columnDefs.add(columnName + " INT" +getConstraints(sInt.constraint()));}//判斷String類型if(anns[0] instanceof SQLString) {SQLString sString = (SQLString) anns[0];// Use field name if name not specified.if(sString.name().length() < 1)columnName = field.getName().toUpperCase();elsecolumnName = sString.name();columnDefs.add(columnName + " VARCHAR(" +sString.value() + ")" +getConstraints(sString.constraint()));}}//數(shù)據(jù)庫(kù)表構(gòu)建語(yǔ)句StringBuilder createCommand = new StringBuilder("CREATE TABLE " + tableName + "(");for(String columnDef : columnDefs)createCommand.append("\n " + columnDef + ",");// Remove trailing commaString tableCreate = createCommand.substring(0, createCommand.length() - 1) + ");";return tableCreate;}/*** 判斷該字段是否有其他約束* @param con* @return*/private static String getConstraints(Constraints con) {String constraints = "";if(!con.allowNull())constraints += " NOT NULL";if(con.primaryKey())constraints += " PRIMARY KEY";if(con.unique())constraints += " UNIQUE";return constraints;}public static void main(String[] args) throws Exception {String[] arg={"com.zejian.annotationdemo.Member"};for(String className : arg) {System.out.println("Table Creation SQL for " +className + " is :\n" + createTableSql(className));}} }

    推薦博客

      程序員寫代碼之外,如何再賺一份工資?

    輸出結(jié)果:

    Table Creation SQL for com.zejian.annotationdemo.Member is : CREATE TABLE MEMBER( ID VARCHAR(50) NOT NULL PRIMARY KEY, NAME VARCHAR(30) NOT NULL, AGE INT NOT NULL, DESCRIPTION VARCHAR(150) );

    如果對(duì)反射比較熟悉的同學(xué),上述代碼就相對(duì)簡(jiǎn)單了,我們通過傳遞Member的全路徑后通過Class.forName()方法獲取到Member的class對(duì)象,然后利用Class對(duì)象中的方法獲取所有成員字段Field,最后利用field.getDeclaredAnnotations()遍歷每個(gè)Field上的注解再通過注解的類型判斷來(lái)構(gòu)建建表的SQL語(yǔ)句。這便是利用注解結(jié)合反射來(lái)構(gòu)建SQL語(yǔ)句的簡(jiǎn)單的處理器模型。

    ?

    轉(zhuǎn)載于:https://www.cnblogs.com/java-chen-hao/p/11024153.html

    總結(jié)

    以上是生活随笔為你收集整理的框架基础:深入理解Java注解类型(@Annotation)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。

    主站蜘蛛池模板: 欧美日韩一区二区三区在线视频 | 久久精品毛片 | 亚洲字幕av一区二区三区四区 | 成人片在线看 | 亚洲特级毛片 | av免费网址在线观看 | 天天狠天天插天天透 | 精品国产露脸精彩对白 | 欧美wwwwww | 伊人网址| 久久久久久综合 | 天天影视综合 | 特级西西444www大胆免费看 | 91性高潮久久久久久久 | 国产美女被遭强高潮免费网站 | 永久免费看黄 | 色吧综合 | 大尺度叫床戏做爰视频 | 伊人网大 | 狼人色综合 | 久久久久久久久久久久久av | 欧美国产二区 | 日日夜夜添 | 国产女人18毛片水真多 | 国产香蕉一区二区三区 | 亚瑟av在线 | 羞视频在线观看 | 少妇光屁股影院 | 一级激情片 | 欧洲成人在线视频 | 亚洲福利电影网 | 欧美 日韩 国产 成人 | 国产成人久久精品麻豆二区 | 亚洲影院av | 非洲黑寡妇性猛交视频 | 久久久精品免费观看 | 成人综合一区 | 香蕉视频ap | 亚洲黄色中文字幕 | 人成免费在线视频 | 亚洲av高清一区二区三区 | 性爱一级视频 | 欧美体内谢she精2性欧美 | 日本欧美一级片 | 狠狠操导航| 精品一区二区无码 | 偷拍亚洲欧美 | 亚洲av无码专区国产乱码不卡 | 久久久久久一区二区 | 国产成人无码精品久在线观看 | 成人片黄网站久久久免费 | 亚洲三级在线免费观看 | 91极品国产 | av免费网页 | 日本韩国毛片 | 欧美激情国产精品免费 | 熟女国产精品一区二区三 | 西西人体做爰大胆gogo | 天天爱天天插 | 欧美日韩一卡二卡 | 第四色激情 | 91精品国产高潮对白 | 三级无遮挡| 扒开女人屁股进去 | 激情四射网 | 国产aaa | 日本在线免费视频 | 90岁肥老奶奶毛毛外套 | 欧美成人不卡视频 | 午夜激情久久久 | 亚洲蜜桃av | 久久亚洲AV成人无码一二三 | 成人激情自拍 | 欧美91精品久久久久国产性生爱 | 成人片黄网站色大片免费毛片 | 久久盗摄| 国产av人人夜夜澡人人爽 | 欧美极品少妇xxxxⅹ裸体艺术 | 99久久精品日本一区二区免费 | 涩涩视频在线免费看 | 欧美婷婷六月丁香综合色 | 夜夜爽天天爽 | 欧美日韩亚洲另类 | 国产午夜视频在线观看 | 亚洲av熟女国产一区二区性色 | 欧美天堂在线 | 国产成人无码av在线播放dvd | 亚洲国产亚洲 | 伦伦影院午夜理论片 | 国产69精品久久久 | 99视频在线看 | 在线免费观看av不卡 | 四虎精品在永久在线观看 | 色播导航 | 无码任你躁久久久久久老妇 | 青春草国产视频 | 在线你懂的 | 国产理论 | 欧美性aaa|