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

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > java >内容正文

java

Java注解库_Java 注解详解

發布時間:2025/3/21 java 46 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Java注解库_Java 注解详解 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

本文部分摘自 On Java 8

基本語法

注解是 Java 5 所引入的眾多語言變化之一,是附加在代碼中的一些元信息,用于一些工具在編譯、運行時進行解析和使用,起到說明、配置的功能。注解不會也不能影響代碼的實際邏輯,僅僅起到輔助性的作用,包含在 java.lang.annotation 包中

注解的語法十分簡單,只要在現有語法中添加 @ 符號即可,java.lang 包提供了如下五種注解:

@Override

表示當前的方法定義將覆蓋基類的方法,如果你不小心把方法簽名拼錯了,編譯器就會發出錯誤提示

@Deprecated

如果使用該注解的元素被調用,編譯器就會發出警告信息,表示不鼓勵程序員使用

@SuppressWarnings

關閉不當的編譯器警告信息

@SafeVarargs

禁止對具有泛型可變參數的方法或構造函數的調用方發出警告

@FunctionalInterface

聲明接口類型為函數式接口

定義注解

注解的定義看起來和接口的定義很像,事實上它們和其他 Java 接口一樣,也會被編譯成 class 文件

@Target(ElementType.METHOD)

@Retention(RetentionPolicy.RUNTIME)

public @interface TestAnnotation {}

除開 @ 符號, @Test 的定義看起來更像一個空接口。注解的定義也需要一些元注解,元注解用于注解其他的注解

注解

解釋

@Target

表示注解可以用于哪些地方。可能的 ElementType 參數包括:

CONSTRUCTOR:構造器的聲明

FIELD:字段聲明(包括 enum 實例)

LOCAL_VARIABLE:局部變量聲明

METHOD:方法聲明

PACKAGE:包聲明

PARAMETER:參數聲明

TYPE:類、接口(包括注解類型)或者 enum 聲明

@Retention

表示注解信息保存的時長。可選的 RetentionPolicy 參數包括:

SOURCE:注解將被編譯器丟棄

CLASS:注解在 class 文件中可用,但是會被 VM 丟棄

RUNTIME:VM 將在運行期也保留注解,因此可以通過反射機制讀取注解的信息

@Documented

將此注解保存在 Javadoc 中

@Inherited

允許子類繼承父類的注解

@Repeatable

允許一個注解可以被使用一次或者多次(Java8)

不包含任何元素的注解稱為標記注解,上例中的 @Test 就是標記注解。注解通常也會包含一些表示特定值的元素,當分析處理注解的時候,程序可以利用這些值。注解的元素看起來就像接口的方法,但可以為其指定默認值

@Target(ElementType.METHOD)

@Retention(RetentionPolicy.RUNTIME)

public @interface TestAnnotation {

int id();

String description() default "no description";

}

....

public class TestUtils {

// 在方法上使用注解 @TestAnnotation

@UseCase(id = 47, description = "description")

public void test() {

...

}

}

注解元素可用的類型如下所示,如果使用了其他類型,編譯器就會報錯:

所有基本類型(int、float、boolean 等)

String

Class

enum

Annotation

以上類型的數組

如果沒有給出 description 的值,在分析處理這個類的時候會使用該元素的默認值。元素的默認值不能有不確定的值,也就是說,元素要么有默認值,要么就在使用注解時提供元素的值

這里還有另外一個限制:任何非基本類型的元素,無論是在源代碼聲明時還是在注解接口中定義默認值時,都不能使用 null 作為值。如果我們希望表現一個元素的存在或者缺失的狀態,可以自定義一些特殊的值,比如空字符串或者負數用于表達某個元素不存在

注解不支持繼承,你不能使用 extends 關鍵字來繼承 @interface

注解處理器

如果沒有用于讀取注解的工具,那么注解不會比注釋更有用。使用注解中一個很重要的作用就是創建與使用注解處理器。Java 拓展了反射機制的 API 用于幫助你創造這類工具。同時他還提供了 javac 編譯器鉤子在編譯時使用注解

下面是一個非常簡單的注解處理器,我們用它來讀取被注解的 TestUtils 類,并且使用反射機制來尋找 @TestAnnotation 標記

public class TestAnnotationTracker {

public static void trackTestAnnotation(Class> cl) {

for(Method m : cl.getDeclaredMethods()) {

TestAnnotation ta = m.getAnnotation(TestAnnotation.class);

if(ta != null) {

System.out.println(ta.id() + "\n " + ta.description());

}

}

}

public static void main(String[] args) {

trackTestAnnotation(TestUtils.class);

}

}

這里用到了兩個反射的方法:getDeclaredMethods() 和 getAnnotation(),getAnnotation() 方法返回指定類型的注解對象,在本例中就是 TestAnnotation,如果被注解的方法上沒有該類型的注解,返回值就為 null。通過調用 id() 和 description() 方法來提取元素值

使用注解實現對象 - 數據庫映射

當有些框架需要一些額外的信息才能與你的源代碼協同工作,這種情況下注解就會變得十分有用。自定義例如對象/關系映射工具(Hibernate 和 MyBatis)通常都需要 XML 描述文件,而這些文件脫離于代碼之外。除了定義 Java 類,程序員還必須重復的提供某些信息,而例如類名和包名等信息已經在原始類中提供過了,經常會導致代碼和描述文件的同步問題

假設你現在想提供一些基本的對象/關系映射功能,能夠自動生成數據庫表。你可以使用 XML 描述文件來指明類的名字、每個成員以及數據庫映射的相關信息。但是,通過使用注解,你可以把所有信息都保存在 JavaBean 源文件中。為此你需要一些用于定義數據庫表名稱、數據庫列以及將 SQL 類型映射到屬性的注解

首先創建一個用來映射數據庫表的注解,用來修飾類、接口(包括注解類型)或者 enum 聲明

@Target(ElementType.TYPE)

@Retention(RetentionPolicy.RUNTIME)

public @interface DBTable {

String name() default "";

}

如下是修飾字段的注解

@Target(ElementType.FIELD)

@Retention(RetentionPolicy.RUNTIME)

public @interface Constraints {

boolean primaryKey() default false;

boolean allowNull() default true;

boolean unique() default false;

}

public @interface SQLString {

int value() default 0;

String name() default "";

Constraints constraints() default @Constraints;

}

@Target(ElementType.FIELD)

@Retention(RetentionPolicy.RUNTIME)

public @interface SQLInteger {

String name() default "";

Constraints constraints() default @Constraints;

}

@Constraints 代表了數據庫通常提供的約束的一小部分,primaryKey(),allowNull() 和 unique() 元素都提供了默認值,大多數情況下,注解的使用者都不需要輸入太多東西

另外兩個 @interface 定義的是 SQL 類型。如果希望這個框架更有價值的話,我們應該為每個 SQL 類型都定義相應的注解。不過作為示例,兩個元素足夠了。這些 SQL 類型具有 name() 元素和 constraints() 元素。后者利用了嵌套注解的功能,將數據庫列的類型約束信息嵌入其中。注意 constraints() 元素的默認值是 @Constraints,沒有在括號中指明 @Constraints 元素的值,因此,constraints() 的默認值為所有元素都為默認值。如果要使得嵌入的 @Constraints 注解中的 unique() 元素為 true,并作為 constraints() 元素的默認值,你可以像如下定義:

public @interface Uniqueness {

Constraints constraints() default @Constraints(unique = true);

}

下面是一個簡單的,使用了如上注解的類

@DBTable(name = "MEMBER")

public class Member {

@SQLString(30)

String firstName;

@SQLString(50)

String lastName;

@SQLInteger

Integer age;

@SQLString(value = 30, constraints = @Constraints(primaryKey = true))

String reference;

static int memberCount;

public String getReference() { return reference; }

public String getFirstName() { return firstName; }

public String getLastName() { return lastName; }

@Override

public String toString() { return reference; }

public Integer getAge() { return age; }

}

類注解 @DBTable 注解給定了元素值 MEMBER,它將會作為表的名字。類的屬性 firstName 和 lastName 都被注解為 @SQLString 類型并且給了默認元素值分別為 30 和 50,并在嵌入的 @Constraint 注解中設定 primaryKey 元素的值

下面是一個注解處理器的例子,它將讀取一個類文件,檢查上面的數據庫注解,并生成用于創建數據庫的 SQL 命令:

public class TableCreator {

public static void generateSql(String[] classnames) throws Exception {

for (String className : classnames) {

Class> cl = Class.forName(className);

DBTable dbTable = cl.getAnnotation(DBTable.class);

String tableName = dbTable.name();

// 如果表名為空字符串,則使用類名

if (tableName.length() < 1) {

tableName = cl.getName().toUpperCase();

}

List columnDefs = new ArrayList<>();

for (Field field : cl.getDeclaredFields()) {

String columnName = null;

Annotation[] anns = field.getDeclaredAnnotations();

// 該屬性不是列

if (anns.length < 1) {

continue;

}

// 處理整數類型

if (anns[0] instanceof SQLInteger) {

SQLInteger sInt = (SQLInteger) anns[0];

// 如果列名為空字符串,則使用屬性名

if (sInt.name().length() < 1) {

columnName = field.getName().toUpperCase();

} else {

columnName = sInt.name();

}

columnDefs.add(columnName + " INT" + getConstraints(sInt.constraints()));

}

// 處理字符串類型

if (anns[0] instanceof SQLString) {

SQLString sString = (SQLString) anns[0];

if (sString.name().length() < 1) {

columnName = field.getName().toUpperCase();

} else {

columnName = sString.name();

}

columnDefs.add(columnName + " VARCHAR(" + sString.value() + ")" +

getConstraints(sString.constraints()));

}

// 構造并輸出 sql 字符串

StringBuilder createCommand = new StringBuilder("CREATE TABLE " + tableName + "(");

for (String columnDef : columnDefs) {

createCommand.append("\n " + columnDef + ",");

}

String tableCreate = createCommand.substring(0, createCommand.length() - 1) + ");";

System.out.println("Table Creation SQL for " + className + " is:\n" + tableCreate);

}

}

}

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;

}

}

編譯時注解處理

當 @Retention 的 RetentionPolicy 參數被標注為 SOURCE 或 CLASS,此時你無法通過反射去獲取注解信息,因為注解在運行期是不存在的。使用 javac 可以創建編譯時注解處理器,在編譯時掃描和處理注解。你可以自定義注解,并注冊到對應的注解處理器。注解處理器可以生成 Java 代碼,這些生成的 Java 代碼會組成新的 Java 源文件,但不能修改已經存在的 Java 類,例如向已有的類中添加方法。如果你的注解處理器創建了新的源文件,在新一輪處理中注解處理器會檢查源文件本身,在檢測一輪之后持續循環,直到不再有新的源文件產生,然后編譯所有的源文件

我們來編寫一個簡單的注解處理器,如下是注解的定義

@Retention(RetentionPolicy.SOURCE)

@Target({ElementType.TYPE, ElementType.METHOD,

ElementType.CONSTRUCTOR,

ElementType.ANNOTATION_TYPE,

ElementType.PACKAGE, ElementType.FIELD,

ElementType.LOCAL_VARIABLE})

public @interface Simple {

String value() default "-default-";

}

@Retention 的參數為 SOURCE,這意味著注解不會存留在編譯后的 class 文件,因為這對應編譯時處理注解是沒有必要的,在這里,javac 是唯一有機會處理注解的方式

package annotations.simplest;

@Simple

public class SimpleTest {

@Simple

int i;

@Simple

public SimpleTest() {}

@Simple

public void foo() {

System.out.println("SimpleTest.foo()");

}

@Simple

public void bar(String s, int i, float f) {

System.out.println("SimpleTest.bar()");

}

@Simple

public static void main(String[] args) {

@Simple

SimpleTest st = new SimpleTest();

st.foo();

}

}

運行 main 方法,程序就會開始編譯,如下是一個簡單的處理器,作用就是把注解相關的信息打印出來

package annotations.simplest;

import javax.annotation.processing.*;

import javax.lang.model.SourceVersion;

import javax.lang.model.element.*;

import java.util.*;

@SupportedAnnotationTypes("annotations.simplest.Simple")

@SupportedSourceVersion(SourceVersion.RELEASE_8)

public class SimpleProcessor extends AbstractProcessor {

@Override

public boolean process(Set extends TypeElement> annotations,

RoundEnvironment env) {

for(TypeElement t : annotations) {

System.out.println(t);

}

for(Element el : env.getElementsAnnotatedWith(Simple.class)) {

display(el);

}

return false;

}

private void display(Element el) {

System.out.println("==== " + el + " ====");

System.out.println(el.getKind() +// 返回此元素的種類,字段,方法,或是類

" : " + el.getModifiers() +// 返回此元素的修飾符

" : " + el.getSimpleName() +// 返回此元素的簡單名稱

" : " + el.asType());// 返回此元素定義的類型

// 如果元素為CLASS類型,動態向下轉型為更具體的元素類型,并打印相關信息

if(el.getKind().equals(ElementKind.CLASS)) {

TypeElement te = (TypeElement)el;

System.out.println(te.getQualifiedName());

System.out.println(te.getSuperclass());

System.out.println(te.getEnclosedElements());

}

// 如果元素為METHOD類型,動態向下轉型為更具體的元素類型,并打印相關信息

if(el.getKind().equals(ElementKind.METHOD)) {

ExecutableElement ex = (ExecutableElement)el;

System.out.print(ex.getReturnType() + " ");

System.out.print(ex.getSimpleName() + "(");

System.out.println(ex.getParameters() + ")");

}

}

}

使用 @SupportedAnnotationTypes 和 @SupportedSourceVersion 注解來確定支持哪些注解以及支持的 Java 版本

注解處理器需要繼承抽象類 javax.annotation.processing.AbstractProcessor,唯一需要實現的方法就是 process(),這里是所有行為發生的地方。第一個參數獲取到此注解處理器所要處理的注解集合,第二個參數保留了剩余信息,這里我們所做的事情只是打印了注解(只存在一個)。process() 中實現的第二個操作是循環所有被 @Simple 注解的元素,并且針對每一個元素調用 display() 方法。展示所有 Element 自身的基本信息

總結

以上是生活随笔為你收集整理的Java注解库_Java 注解详解的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。

主站蜘蛛池模板: 国产一区=区 | 蜜桃传媒一区二区亚洲 | 在线观看亚洲欧美 | 2019最新中文字幕 | 成人欧美一区二区三区黑人冫 | 中文毛片| 高跟肉丝丝袜呻吟啪啪网站av | 97精品视频在线观看 | 天堂网中文在线 | 国产在线激情 | 成人日韩精品 | 天天干干天天 | 日韩欧美高清在线 | 91精彩刺激对白 | 欧美一区二区三区成人久久片 | 久久综合久色欧美综合狠狠 | 狂野少女电影在线观看国语版免费 | 狠狠插影院 | 光棍福利视频 | 影音先锋中文字幕人妻 | 极品女神无套呻吟啪啪 | 999热精品视频 | 一卡二卡国产 | 一区二区三区亚洲 | 精品免费一区二区 | 欧美性猛交ⅹxx乱大交 | 午夜在线精品 | 国产精品无码一区二区三区三 | 国产91专区| 日本三级影院 | 黄色免费网站在线观看 | 亚洲av无码国产在丝袜线观看 | 在线视频一区二区三区 | 中文字幕精品久久久久人妻红杏1 | 五月天视频网 | 亚洲欧美激情在线观看 | 免费在线观看成人 | 国产黄色大全 | 天天操夜夜操视频 | 成人羞羞国产免费 | 91超薄肉色丝袜交足高跟凉鞋 | 国产日韩欧美日韩大片 | 中文字幕成人网 | 黄色性大片 | 无码人妻丰满熟妇区毛片蜜桃精品 | 曰韩一级片 | 亚洲福利在线视频 | 国产成人精品无码播放 | 搞逼综合网 | 一本色道久久综合亚洲精品小说 | 欧美色图在线观看 | 久操视频免费看 | 色吧综合网 | 欧美三级不卡 | www日韩欧美| 欧美 亚洲 | 成人免费观看网站 | 黄页免费视频 | xxxx视频在线| 亚洲成人第一区 | 国产精品一区二区在线免费观看 | 99久久人妻无码中文字幕系列 | 亚洲av无码日韩精品影片 | 欧美日韩亚洲另类 | 天天综合永久入口 | 精品视频在线播放 | 91在线无精精品白丝 | 成人在线观看www | 国产黄色片免费看 | 日本一道在线 | 国产网站免费在线观看 | 日韩福利在线视频 | 无码日韩精品一区二区 | 国产青青草 | 亚洲a一区二区 | 日本女人毛茸茸 | 中国肥胖女人真人毛片 | 91免费视频网 | 国内精品国产三级国产aⅴ久 | 免费观看成年人网站 | 午夜精品偷拍 | 午夜羞羞网站 | 一本一道波多野结衣一区二区 | 一本久久综合 | 欧美精品一二 | 全黄性性激高免费视频 | 久久综合一本 | 毛片网站视频 | www.久久爱 | 美女被草 | 国产99在线播放 | www免费黄色 | 亚洲一区二区三区在线视频 | 韩国日本中文字幕 | 亚洲色图第一页 | 中文字幕在线观看二区 | 自拍一级片 | 国产视频手机在线播放 | 欧美香蕉在线 |