Java筆記:反射,註解

来源:https://www.cnblogs.com/guyuyun/archive/2020/06/26/13193546.html
-Advertisement-
Play Games

一、反射 1. 反射機制 反射機制的相關類除了一個java.lang.Class,其餘都在java.lang.reflect包下。反射機制用於讀取class位元組碼文件,需要註意,JVM載入位元組碼到記憶體中時都只會保存一份,多次讀取class文件時不用擔心也會載入多次。反射機制相關的常用類: java. ...


一、反射

1. 反射機制

反射機制的相關類除了一個java.lang.Class,其餘都在java.lang.reflect包下。
反射機制用於讀取class位元組碼文件,需要註意,JVM載入位元組碼到記憶體中時都只會保存一份,多次讀取class文件時不用擔心也會載入多次。
反射機制相關的常用類:

  • java.lang.Class:代表整個類的位元組碼,表示一個類型。
  • java.lang.reflect.Method:代表位元組碼中的方法位元組碼,表示一個方法。
  • java.lang.reflect.Constructor:代表位元組碼中的構造方法位元組碼,表示一個構造方法。
  • java.lang.reflect.Field:代表位元組碼中的屬性位元組碼,表示一個屬性。

 

2. 反射類位元組碼Class(類/類型)

獲取類的位元組碼(java.lang.Class類)有三種方式:

  • 第一種方式:通過Class類的靜態方法forName,例如Class c1 = Class.forName("java.lang.String");就表示獲取到了String這個類的class位元組碼,註意,這是Class類下的一個靜態方法,參數需要是完整的包名。另外,Class.forName方法的使用會導致類的載入,也就是說如果希望只是執行一個類的靜態代碼塊,並不執行其他的代碼,就可以使用這個方法來進行類的載入,此時,自然就會去執行對應的靜態代碼了。
  • 第二種方式:通過Object類的getClass方法,例如String s = "abc"; Class c2 = s.getClass();,即通過任何類對象的getClass方法就可以拿到對應了類位元組碼了,並且因為JVM只會在記憶體中載入一份相同類的位元組碼,所以這個例子的c2和第一種方式的c1使用雙等號判斷返回結果是true。
  • 第三種方式:通過類的class屬性,例如Class c3 = String.class;,java中任何類型都有class屬性。

Class中常用的方法:

  • String getName():返回類的完整類名(包含包路徑)。
  • String getsimpleName():返回類的簡類名(類定義名稱)。
  • Field[] getFields():獲取Class中所有public類型的Field對象(屬性)。
  • Field[] getDeclaredFields():獲取Class中所有的Field對象(屬性)。
  • Field getDeclaredField(String name):獲取指定名稱的Field對象(屬性)。
  • Method[] getDeclaredMethods():獲取所有的Method對象(方法)。
  • Method getDeclaredMethod(String name, Class<?>... parameterTypes):根據方法名稱和參數類型列表獲取Method對象(方法),例如“userClass.getDeclaredMethod("login", String.class, int.class);”。
  • Constructor<?>[] getDeclaredConstructors():獲取所有的Constructor對象(構造方法)。
  • Constructor<T> getDeclaredConstructor(Class<?>... parameterTypes):獲取指定參數類型列表的Constructor對象(構造方法),例如“userClass.getDeclaredConstructor(String.class, int.class);”。
  • Class<? super T> getSuperclass():獲取類的父類。
  • Class<?>[] getInterfaces():獲取所有類實現的介面。

 

3. 反射屬性位元組碼Field(欄位/屬性)

獲取Field需要先獲取到對應的類位元組碼Class,然後才能從類中獲取到對應的Field(java.lang.reflect.Field)。
Field常用方法:

  • Class<?> getType():返回屬性的數據類型。
  • String getName():返回屬性的名稱。
  • int getModifiers():返回修飾符列表的代號,此代號可以使用java.lang.reflect.Modifier的靜態方法toString方法傳入代號獲取到具體的修飾符名稱列表。
  • void set(Object obj, Object value):給指定對象的Field對象賦予值value。
  • Object get(Object obj):獲取指定對象的Field值(屬性值)。
  • void setAccessible(boolean flag):設置為true時表示打破封裝,如果不調用這個方法設置為true的話就沒辦法獲取對象的私有屬性了,調用這個方法之後就可以獲取到所有的屬性了,包括私有屬性。

 

4. 反射方法位元組碼Method(方法)

獲取Method需要先獲取到對應的類位元組碼Class,然後才能從類中獲取到對應的Method(java.lang.reflect.Method)。

Method中的常用方法:

  • Class<?> getReturnType():獲取返回值的數據類型。
  • Class<?>[] getParameterTypes():獲取方法的參數類型列表。
  • int getModifiers():返回修飾符列表的代號,此代號可以使用java.lang.reflect.Modifier的靜態方法toString方法傳入代號獲取到具體的修飾符名稱列表。
  • Object invoke(Object obj, Object... args):調用指定對象的方法。

 

5. 反射構造方法Constructor(構造方法)

獲取Constructor需要先獲取到對應的類位元組碼Class,然後才能從類中獲取到對應的Method(java.lang.reflect.Constructor)。

Constructor中的常用方法:

  • int getModifiers():返回修飾符列表的代號,此代號可以使用java.lang.reflect.Modifier的靜態方法toString方法傳入代號獲取到具體的修飾符名稱列表。
  • T newInstance(Object... initargs):使用newInstance方法創建一個實例對象。

 

二、註解

1. 定義註解(Annotation)

註解,或者稱之為註釋,也是一種引用數據類型,編譯之後也會生成class文件,具體用法見示例:

[修飾符列表] @interface 註解類型名{
    // 屬性定義
}

 

註解定義示例:

// 無屬性的註解定義
public @interface MyAnnotation{
    // 這裡面什麼都不寫,表示沒有屬性
}


// 有屬性的註解定義
public @interface MyAnnotation2{
    // 定義一個沒有預設值的屬性,在使用這個註解的時候就必須給這個屬性傳值
    // 註意,註解的屬性定義是有小括弧的,但它不是方法,就只是屬性
    String name();
    
    // 使用default給屬性指定預設值,有預設值的屬性在使用時就可以不用給這個屬性傳值了
    int id() default 2333;
}


// 屬性只有一個,且為value時,使用時可以不用指定屬性名稱
public @interface MyAnnotation3{
    String value();
}

 

註解使用示例:

// 使用:直接在類、方法、屬性、形參、註解等上面使用形如”@註解類型名“的格式即可。
// 註解的使用其實就像修飾符一樣在定義的前面加上就可以,但是通常的使用習慣是在定義上一行進行添加
public class AnnotationTest {
    public static void main(String[] args) {

    }

    // 相當於:@MyAnnotation private int id;
    @MyAnnotation
    private int id;

    // 註解只有一個屬性,且屬性名為value時,可以不用指定屬性名
    @MyAnnotation3("hello")
    public AnnotationTest() {
    }

    // 定義了沒有預設值的屬性的註解,就必須給這個屬性傳值,有預設值的屬性可以傳,也可以不傳
    @MyAnnotation2(name = "zhangsan")
    public static void func() {
        @MyAnnotation2(name = "lisi", id = 666)
        int i = 10;
    }

    // 相當於:@MyAnnotation public void func2(@MyAnnotation String name)
    @MyAnnotation
    public void func2(@MyAnnotation String name) {
        System.out.println(name);
    }
}

 

註解屬性類型:定義註解的屬性時,屬性的類型可以是byte、short、int、long、float、double、boolean、char、String、Class、枚舉類型,以及這幾種類型的數組形式,不能是其他的類型。有一個小技巧,屬性如果是數組,並且使用時傳入的數組元素只有一個的話,定義數組的大括弧是可以不寫的。

 

2. Java內置註解

內置註解在java.lang包下,常用的有:

  • @Override:這個註解只能註解方法,並且只是給編譯器在編譯階段做參考用的,和運行階段的代碼沒有關係,編譯器在編譯時會檢查這個方法是否是重寫的父類方法,如果不是則會報錯。
  • @Deprecated:表示被標註的類、方法等元素已經過時了,不建議使用。在IDEA中,被標註的方法等會出現一條橫線,提示你這個方法已過時。

 

3. 元註解

用來標註“註解類型”的註解,即註解的註解,稱之為元註解,在java.lang.annotation包下。常用的元註解有:

  • @Target(ANNOTATION_TYPE):用來指定被標註的註解可以出現在哪些位置上,參數為枚舉類型ElementType的數組,具體有哪些枚舉值可以參考幫助文檔,如“@Target(ElementType.METHOD)”表示被標註的註解只能出現在方法上。
  • @Retention(RUNTIME):用來指定被標註的註解最終保存在哪裡,參數是一個枚舉類型RetentionPolicy,有三個枚舉值,“@Retention(RetentionPolicy.SOURCE)”表示被標註的註解保存在java源文件中,並不會出現在編譯之後的class文件中,“@Retention(RetentionPolicy.CLASS)”表示被標註的註解保存在class文件中,“@Retention(RetentionPolicy.RUNTIME)”表示被標註的註解保存在class文件中,並且可以被反射機制讀取出來。

 

4. 反射註解

以類的註解為例,首先獲取到類的位元組碼對象後,使用Class對象的方法進行反射,常用的方法有:

  • boolean isAnnotationPresent(MyAnnotation.class):判斷一個類是否有指定的註解,這裡需要傳入一個指定註解的類位元組碼對象。
  • getAnnotation(MyAnnotation.class):獲取類的指定註解對象,這裡需要傳入一個指定註解的類位元組碼對象。

屬性獲取:通過反射拿到註解對象之後,就可以通過調用方法(其實是屬性)的形式獲取屬性值,因為註解定義屬性時,本身就自帶小括弧,所以看起來就是在調用方法了,如“String name = annotationObj.name();”
註:方法、屬性等的註解獲取也是和上面的方法一樣,而且調用的方法等大多也都是一樣的。

 

5. 註解的作用

註解通常是通過反射機制去檢查被註解的類、方法等是否滿足要求,比如@Override就是檢查被註解的方法是否是重寫父類的方法,如果不是就會編譯報錯。

 


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 按照指定字元進行合併或拆分是經常碰到的場景,MySQL在合併的寫法上比較簡單,但是按指定字元拆分相對比較麻煩一點(也就是要多寫一些字元)。本文將舉例演示如何進行按照指定字元合併及拆分。 1、 合併 MySQL資料庫中按照指定字元合併可以直接用group_concat來實現。 創建測試表 mysql> ...
  • 從www.codeaurora.org同步Android for MSM項目的代碼時,由於q的存在經常失敗,怎樣解決同步代碼的問題呢? 方法如下: 1.打開站長之家>站長工具 > 海外網站測速,對codeaurora.org進行分析。 2.將功能變數名稱codeaurora.org指向測試出來的“解析IP” ...
  • 一、靜態註冊實現開機啟動 1.在之前的連載中,我們編寫的是動態註冊,用到了內部類等。動態註冊只能在程式啟動之後才能生效。接下來我們將要使用靜態註冊的方式進行註冊。(可以舉例開機啟動項) package com.example.broadcasttest2; ​ import android.cont ...
  • 在項目中用 require('./Download.vue') 引入一個組件的時缺少.default 會報錯: Failed to mount component: template or render function not defined <template> <div id="app"> < ...
  • 1. 解決辦法: 當在最後提交的時候,出現的錯誤。 解決辦法: git remote rm origin 執行下麵代碼: git remote add origin https://github.com/haohuihai/tour.git 最後提交到倉庫: git push -u origin m ...
  • 在Canvas API中,上下文CanvasRenderingContext2D對象提供了一個繪製圓與圓弧的方法,其基本格式為: void arc(in float x, in float y, in float radius, in float startAngle, in float endAn ...
  • 在Canvas API中,上下文CanvasRenderingContext2D對象提供了一個與坐標旋轉相關的方法: void rotate(in float angle); // 按給定的弧度順時針旋轉angle 利用rotate()方法可以很方便地將繪製的圖形旋轉。下麵我們通過對正方形進行旋轉變 ...
  • 一、列印char字元 #include<stdio.h> #pragma warning(disable:4996) ​ int D10_1_PrintCharacter(void) { char ch; ​ printf("Please enter a character:\n"); //ch = ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...