日韩av黄I国产麻豆传媒I国产91av视频在线观看I日韩一区二区三区在线看I美女国产在线I麻豆视频国产在线观看I成人黄色短片

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 >

JAVA注解和反射(笔记)

發布時間:2023/12/3 39 豆豆
生活随笔 收集整理的這篇文章主要介紹了 JAVA注解和反射(笔记) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

注解簡介

  • Annotation是從JDK5.0開始引入的新技術).

  • Annotation的作用 :

    • 不是程序本身(可以對程序作出解釋.(這一點和注釋(comment)沒什么區別)
    • 可以被其他程序(比如:編譯器等)讀取.
  • Annotation的格式:

    注解是以"@注釋名"在代碼中存在的, 還可以添加一些參數值,例如:@SuppressWarnings(value=“unchecked”).

  • Annotation在哪里使用?

    可以附加在package , class , method , field等上面,相當于給他們添加了額外的輔助信息,我們可以通過反射機制編程實現對這些元數據的訪問

  • 內置注解

  • @Override : 定義在java.lang.Override中,此注釋只適用于修辭方法, 表示一個方法聲明打算重寫超類中的另一個方法聲明.

  • @Deprecated :定義在java.lang.Deprecated中,此注釋可以用于修辭方法,屬性,類,表示不鼓勵程序員使用這樣的元素,通常是因為它很危險或者存在更好的選擇.

  • @SuppressWarnings : 定義在java.lang.SuppressWarnings中,用來抑制編譯時的警告信息,與前兩個注釋有所不同,你需要添加一-個參數才能正確使用,這些參數都是已經定義好了的,我們選擇性的使用就好了.

    @SuppressWarnings(“l”)

    @SuppressWarnings(“unchecked”)

    @SuppressWarnings(value={“unchecked”,“deprecation”})

  • package com.kuang.demo01; public class Test01 extends Object{@Override//重寫方法public String toString() {return super.toString(); }@Deprecated//表示棄用方法,不推薦使用,但是仍然可以使用public static void test(){System.out.println("asdfasfsa"); }@SuppressWarnings("all")//抑制警告public static void test01(){int age;}public static void main(String[] args) {test();test01();} }

    元注解

  • 元注解的作用就是負責注解其他注解, Java定義了4個標準的meta -annotation類型,他們被用來提供對其他annotation類型作說明.
  • 這些類型和它們所支持的類在java.lang.annotation包中可以找到.( @ Target , @Retention,@Documented , @Inherited )
    • @Target :用于描述注解的使用范圍(即:被描述的注解可以用在什么地方)
    • @Retention :表示需要在什么級別保存該注釋信息,用于描述注解的生命周期
      • (SOURCE 源碼< CLASS < RUNTIME)
    • @Document:說明該注解將被包含在javadoc中
    • @Inherited: 說明子類可以繼承父類中的該注解
  • package com.kuang.demo01;import java.lang.annotation.*; @MyAnnotation public class Test01 {void test(){} } //定義一個注解 //Target 表示我們的注解可以用在哪些地方. @Target(value = {ElementType.METHOD, ElementType.TYPE}) //Retention表示我們的注解在什么地方還有效。 // runtime>class>sources @Retention(value = RetentionPolicy.RUNTIME) //Documented表示是否將我們的注解生成在Javadoc中 @Documented //Inherited子類可以繼承父類的注解 @Inherited @interface MyAnnotation{ }

    自定義注解

  • 使用@interface自定義注解時,自動繼承了java.lang .annotation.Annotation接口

  • 分析:

    • @ interface用來聲明一個注解,格式: public @ interface注解名{定義內容}
    • 其中的每一個方法實際 上是聲明了一個配置參數.
    • 方法的名稱就是參數的名稱.
    • 返回值類型就是參數的類型(返回值只能是基本類型,Class , String , enum ).

    [外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-q65W1rPq-1608789860775)(C:\Users\王東梁\AppData\Roaming\Typora\typora-user-images\image-20201224003234223.png)]

    • 可以通過default來聲明參數的默認值
    • 如果只有一個參數成員, 一般參數名為value //只有value才能省略參數名
    • 注解元素必須要有值,我們定義注解元素時,經常使用空字符串,0作為默認值.
  • package com.kuang.demo01; import java.lang.annotation.*; public class Test01 {public static void main(String[] args) {}//注解可以顯示賦值,如果沒有默認值 ,我們就必須給注解賦值@MyAnnotation2(name = "趙大寶",age = 12)public void test(){}@MyAnnotation3("baobao")//參數只有一個,且參數名為valuepublic void test1(){} }@Target({ElementType.METHOD,ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) @interface MyAnnotation2{//注解的參數:參數類型+參數名();String name() default "";int age() default 0;int id() default -1;// 如果默認值為-1,代表不存在。String[] schools() default {"清華大學,遼寧大學"}; }@Target(value = {ElementType.TYPE,ElementType.METHOD}) @Retention(RetentionPolicy.RUNTIME) @interface MyAnnotation3{//只有一個參數時,參數名為value時,使用時不需參數名String value(); }

    靜態VS動態語言

    動態語言

  • 是一類在運行時可以改變其結構的語言:例如新的函數、對象、甚至代碼可以被引進,已有的函數可以被刪除或是其他結構上的變化。通俗點說就是在運行時代碼可以根據某些條件改變自身結構。
  • 主要動態語言: Object-C、 C#、 JavaScript、 PHP、Python等。
  • 靜態語言

  • 與動態語言相對應的,運行時結構不可變的語言就是靜態語言。如Java、 C、C++。
  • Java不是動態語言,但Java可以稱之為“準動態語言”。即Java有一 定的動態性,我們可以利用反射機制獲得類似動態語言的特性。Java的動態性讓編程的時候更加靈活!
  • Java Reflection

  • Reflection (反射)是Java被視為動態語言的關鍵,反射機制允許程序在執行期借助于Reflection API取得任何類的內部信息,并能***直接操作任意對象的內部屬性及方法***。

    Class C= Class forName("java.lang String")
  • 加載完類之后,在堆內存的方法區中就產生了一個Class類型的對象(一個類只有一個Class對象),這個對象就包含了完整的類的結構信息。我們可以通過這個對象看到類的結構。這個對象就像一-面鏡子, 透過這個鏡子看到類的結構,所以我們形象的稱之為:反射。

  • [外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-1PXhtR2x-1608789860779)(C:\Users\王東梁\AppData\Roaming\Typora\typora-user-images\image-20201224095555221.png)]

    Java反射機制研究及應用

    Java反射機制提供的功能

  • 在運行時判斷任意一個對象所屬的類
  • 在運行時構造任意一個類的對象
  • 在運行時判斷任意一個類所具有的成員變量和方法
  • 在運行時獲取泛型信息
  • 在運行時調用任意一個對象的成員變量和方法:
  • 在運行時處理注解
  • 生成動態代理
  • Java反射優點和缺點

  • 優點:可以實現動態創建對象和編譯,體現出很大的靈活性
  • 缺點:對性能有影響,使用反射基本上是一種解釋操作,我們可以告訴JVM,我們希望做什么并且它滿足我們的要求。這類操作總是慢于直接執行相同的操作。
  • 反射相關的主要API

  • java.lang.Class:代表一個類
  • java.lang.reflect.Method :代表類的方法
  • java.lang.reflect.Field :代表類的成員變量
  • java.lang.reflect.Constructor :代表類的構造器
  • 獲得反射對象

    package com.kuang.demo01; public class Test02 {public static void main(String[] args) throws ClassNotFoundException {/*通過反射獲取類的Class對象,*一個類只有一個Class對象,所以c1,c2,c3的hashcode相同*一個類被加載后,整個類的結構都會被封裝在Class對象中*/Class c1 = Class.forName("com.kuang.demo01.User");System.out.println(c1.getName());//com.reflection.UserClass c2 = Class.forName("com.kuang.demo01.User");System.out.println(c2.hashCode());Class c3 = Class.forName("com.kuang.demo01.User");System.out.println(c3.hashCode());}}class User{private String name;private int id;private int age;public User(){}public User(String name, int id, int age) {this.name = name;this.id = id;this.age = age;}public String getName() {return name;}public void setName(String name) {this.name = name;}public int getId() {return id;}public void setId(int id) {this.id = id;}public int getAge() {return age;}public void setAge(int age) {this.age = age;}@Overridepublic String toString() {return "User{" +"name='" + name + '\'' +", id=" + id +", age=" + age +'}';} }

    Class類

    • 在Object類中定義了以下的方法,此方法將被所有子類繼承
    public final Class getClass()
    • 以上的方法返回值的類型是一 個Class類,此類是Java反射的源頭,實際上所謂反射從程序的運行結果來看也很好理解,即:可以通過對象反射求出類的名稱。
    • 對象照鏡子后可以得到的信息:某個類的屬性、方法和構造器、某個類到底實現了哪些接口。
    • 對于每個類而言,JRE都為其保留一個不變的Class類型的對象。-一個Class對象包含了特定某個結構(class/interface/enum/annotation/primitive type/void/[)的有關信息。
    • Class本身也是一個類
    • Class 對象只能由系統建立對象
    • 一個加載的類在JVM中只會有一 個Class實例
    • 一個Class對象對應的是一個加載到JVM中的一個.class文件
    • 每個類的實例都會記得自己是由哪個Class實例所生成
    • 通過Class可以完整地得到一個類中的所有被加載的結構
    • Class類 是Reflection的根源,針對任何你想動態加載、運行的類) 唯有先獲得相應的Class對象

    Class類的常用方法

    [外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-97hc1j9Y-1608789860781)(C:\Users\王東梁\AppData\Roaming\Typora\typora-user-images\image-20201224101518888.png)]

    獲取Class類的實例

    a)若已知具體的類, 通過類的class屬性獲取, 該訪法最為安全可靠,程序性能最高。

    Class class = Person.class;

    b)已知某個類的實例, 調用該實例的getClass()方法獲取Class對象

    Class class = person.getClass();

    c)已知一 個類的全類名,且該類在類路徑下,可通過Class類的靜態方法forName()獲取可能拋出ClassNotFoundException

    Class class = Class.forName("demo01.Student");

    d)內置基本數據類型可以直接用類名.Type

    e)還可以利用ClassLoader我們之 后講解

    package com.kuang.demo01; public class Test03{public static void main(String[] args) throws ClassNotFoundException {Person s1 = new Student();System.out.println("這個人是"+s1.name);//方式一:通過對象獲取Class c1 = s1.getClass();System.out.println(c1.hashCode());//方式二:通過forname獲取Class c2 = Class.forName("com.kuang.demo01.Student");System.out.println(c2.hashCode());//通過類名.class獲得Class c3 = Student.class;System.out.println(c3.hashCode());//方式四:基本內置類型的包裝類都有一個TYPE屬性Class c4 = Integer.TYPE;System.out.println(c4);//獲得父類類型Class c5 = c1.getSuperclass();System.out.println(c5);} } class Person{public String name;public Person(){}public Person(String name){this.name = name;}@Overridepublic String toString() {return "Person{" +"name='" + name + '\'' +'}';} } class Student extends Person{public Student(){this.name = "Student";} } class Teacher extends Person{public Teacher(){this.name = "Teacher";} }

    有Class對象的類型

    • class: 外部類成員(成員內部類,靜態內部類),局部內部類,匿名內部類。
    • interface: 接口
    • []:數組
    • enum:枚舉
    • annotation:注解@interface
    • primitive type:基本數據類型
    • void
    package com.kuang.demo01;import java.lang.annotation.ElementType; public class Test04 {public static void main(String[] args) {Class c1 = Object.class; //類 .Class c2 = Comparable.class; //按口Class c3 = String[].class; //- -維數組Class c4 = int[][].class; //二維數組Class c5 = Override.class; //注解Class c6 = ElementType.class; //枚舉Class c7 = Integer.class; //基本數據類型Class c8 = void.class; //voidClass c9 = Class.class; //ClassSystem.out.println(c1);//class java.lang.ObjectSystem.out.println(c2);//interface java.lang.ComparableSystem.out.println(c3);//class [Ljava.lang.String;System.out.println(c4);//class [[ISystem.out.println(c5);//interface java.lang.OverrideSystem.out.println(c6);//class java.lang.annotation.ElementTypeSystem.out.println(c7);//class java.lang.IntegerSystem.out.println(c8);//voidSystem.out.println(c9);//class java.lang.Class//只要元素類型與維度一樣,就是同一個Class.int[] a = new int[10];int[] b = new int[100];System.out.println(a.getClass().hashCode());//1163157884System.out.println(b.getClass().hashCode());//1163157884} }

    Alt加鼠標滾輪(多行單列CV)

    [外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-u9SBbsk4-1608789860783)(C:\Users\王東梁\AppData\Roaming\Typora\typora-user-images\image-20201224104141619.png)]

    JAVA內存分析

    [外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-OJsmiRX3-1608789860785)(C:\Users\王東梁\AppData\Roaming\Typora\typora-user-images\image-20201224104608420.png)]

    類的加載與ClassLoader的理解

    加載:

    將class文件字節碼內容加載到內存中,并將這些靜態數據轉換成方法區的運行時數據結構,然后生成一個代表這個類的java.lang.Class對象.

    鏈接:

    將Java類的二進制代碼合并到JVM的運行狀態之中的過程。

    • 驗證:確保加載的類信息符合JVM規范,沒有安全方面的問題
    • 準備:正式為類變量(static) 分配內存并設置類變量默認初始值的階段,這些內存都將在方法區中進行分配。
    • 解析:虛擬機常量池內的符號引用(常量名)替換為直接引用(地址)的過程。

    初始化:

    • 執行類構造器< clinit> ()方法的過程。類構造器< clinit> ()方法是由編譯期自動收集類中所有類變量的賦值動作和靜態代碼塊中的語句合并產生的。(類構造 器是構造類信息的,不是構造該類對象的構造器)。
    • 當初始化一個類的時候,如果發現其父類還沒有進行初始化,則需要先觸發其父類的初始化。
    • 虛擬機會保證一 個類的 ()方法在多線程環境中被正確加鎖和同步。

    [外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-fFPjcKkb-1608789860786)(C:\Users\王東梁\AppData\Roaming\Typora\typora-user-images\image-20201224110150937.png)]

    [外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-VNVNjvSa-1608789860786)(C:\Users\王東梁\AppData\Roaming\Typora\typora-user-images\image-20201224105950235.png)]

    package com.kuang.demo01;import java.lang.annotation.ElementType; public class Test04 {public static void main(String[] args) {A a=new A();System.out.println(A.m);//100/*1.加載到內存,產生一個類對應Class對象2.鏈接,鏈接結束后m=03.初始化<clinit>(){System. out . println( "A類靜態代碼塊初始化") ;m = 300;m=100;}m=100*/} } class A {static {System.out.println("A類靜態代碼塊初始化");m = 300;}static int m = 100;public A() {System.out.println("A類的參構造初始化");} }

    類初始化發生時間

    類的主動引用(一定會發生類的初始化))

    • 當虛擬機啟動,先初始化main方法所在的類
    • new一個類的對象
    • 調用類的靜態成員(除了final常量)和靜態方法
    • 使用java.lang.reflect包的方法對類進行反 射調用
    • 當初始化一個類, 如果其父類沒有被初始化,則先會初始化它的父類

    類的被動引用(不會發生類的初始化)

    • 當訪問一個靜態域時,只有真正聲明這個域的類才會被初始化。如:當通過子類引用父類的靜態變量,不會導致子類初始化
    • 通過數組定義類引用,不會觸發此類的初始化
    • 引用常量不會觸發此類的初始化(常量在鏈接階段就存入調用類的常量池中了)
    package com.kuang.demo01;public class Test04 {static {System.out.println("main類被加載");}public static void main(String[] args) throws ClassNotFoundException {//1.主動引用//Son son = new Son();/** main類被加載* 父類被加載* 子類被加載* *///反射也會產生主動引用//Class.forName ("com.reflection.Son");/** main類被加載* 父類被加載* 子類被加載* *///不會產生類的引用的方法//System.out.println(Son.b);/** main類被加載* 父類被加載* 2* *///Son[] array = new Son[5];/*main類被加載*/System.out.println(Son.M) ;/** main類被加載* 1* */} } class Father {static int b = 2;static {System.out.println("父類被加載");} } class Son extends Father {static {System.out.println("子類被加載");}static int m = 100;static final int M = 1; }

    類加載器

    類加載的作用:將class文件字節碼內容加載到內存中,并將這些靜態數據轉換成方法區的運行時數據結構,然后在堆中生成一個代表這個類的java.lang(Class對象)作為方法區中類數據的訪問入口。

    類緩存:標準的JavaSE類加載器可以按要求查找類,但一旦某企類被加載到類加載器中,它將維持加載(緩存) 一段時間。不過JVM垃圾回收機制可以回收這些Class對象

    類加載器作用是用來把類(class)裝載進內存的。

    雙親委派機制:如果自己定義和jdk同名的類,運行時虛擬機會在系統的類加載器中尋找,再去擴展類加載器中尋找,再去根加載器中尋找,如果存在同名的類,會使用根加載器中的類,而不使用自己定義的類(保證安全性)

    [外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-Fr0RcHcm-1608789860787)(C:\Users\王東梁\AppData\Roaming\Typora\typora-user-images\image-20201224112320572.png)]

    [外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-Hd6KjVQy-1608789860788)(C:\Users\王東梁\AppData\Roaming\Typora\typora-user-images\image-20201224113637305.png)]

    創建運行時類的對象

    獲取運行時類的完整結構

  • 通過反射獲取運行時類的完整結構Field、Method, Constructor、 Superclass、 Interface、 Annotation
    • 實現的全部接口
    • 所繼承的父類
    • 全部的構造器
    • 全部的方法
    • 全部的Field
    • 注解
  • package com.kuang.demo01;import sun.reflect.misc.MethodUtil;import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.lang.reflect.Member; import java.lang.reflect.Method;//獲得類的信息 public class Test06 {public static void main(String[] args) throws Exception {Class c1 = Class.forName("com.kuang.demo01.User");//獲得包名+類名User user = new User();Class c2 = user.getClass();//獲得類的信息System.out.println(c1.getName());//獲得包名+類名System.out.println(c1.getSimpleName());//獲得類名//獲得類的屬性System.out.println("=======================");Field[] fields = c1.getFields();//獲取類的公開屬性和父類的公開屬性fields = c1.getDeclaredFields();//獲取類的任何屬性for (Field field : fields) {System.out.println(field);}//獲得指定屬性的值Field name = c1.getDeclaredField("name");System.out.println(name);//獲得類的方法System.out.println("=========================");Method[] methods = c1.getMethods();//獲得本類和父類的所有public方法for (Method method : methods) {System.out.println("methods " + method);}System.out.println("=========================");Method[] decmethods = c1.getDeclaredMethods();//獲得本類的所有方法for (Method method : decmethods) {System.out.println("decmethods " + method);}//獲得指定方法//需要傳參數的原因:存在重載,參數可找到指定的方法System.out.println("=========================");Method getName = c1.getMethod("getName", null);Method setName = c1.getMethod("setName", String.class);System.out.println(getName);System.out.println(setName);//獲得構造器System.out.println("=========================");Constructor[] constructors = c1.getConstructors();for (Constructor constructor : constructors) {System.out.println("getConstructors " + constructor);}System.out.println("=========================");Constructor[] constructors1 = c1.getDeclaredConstructors();for (Constructor constructor : constructors1) {System.out.println("getDeclaredConstructors " + constructors1);}//獲得指定的構造器Constructor getDeclaredConstructor = c1.getDeclaredConstructor(String.class, int.class);System.out.println("指定構造器" + getDeclaredConstructor);} } package com.kuang.demo01; public class Test02 {public static void main(String[] args) throws ClassNotFoundException {/*通過反射獲取類的Class對象,*一個類只有一個Class對象,所以c1,c2,c3的hashcode相同*一個類被加載后,整個類的結構都會被封裝在Class對象中*/Class c1 = Class.forName("com.kuang.demo01.User");System.out.println(c1.getName());//com.reflection.UserClass c2 = Class.forName("com.kuang.demo01.User");System.out.println(c2.hashCode());Class c3 = Class.forName("com.kuang.demo01.User");System.out.println(c3.hashCode());}}class User{private String name;private int id;private int age;public User(){}public User(String name, int id, int age) {this.name = name;this.id = id;this.age = age;}public User(String name, int id) {this.name = name;this.id = id;}public String getName() {return name;}public void setName(String name) {this.name = name;}public int getId() {return id;}public void setId(int id) {this.id = id;}public int getAge() {return age;}public void setAge(int age) {this.age = age;}@Overridepublic String toString() {return "User{" +"name='" + name + '\'' +", id=" + id +", age=" + age +'}';} }

    小結

  • 在實際的操作中, (取得類的信息的操作代碼并不會經常開發)
  • 一定要熟悉java.lang.reflect包的作用,反射機制。.
  • 如何取得屬性、方法、構造器的名稱,修飾符等。
  • Class對象作用

    創建類的對象:

    調用Class對象的**newInstance()**方法

    • 類必須有一個無參數的構造器。

    • 類的構造器的訪問權限需要足夠

    思考?難道沒有無參的構造器就不能創建對象了嗎?

    只要在操作的時候明確的調用類中的構造器,并將參數傳遞進去之后,才可以實例化操作。步驟如下:

    1)通過Class類的getDeclaredConstructor(Class … parameterTypes)取得本類的指定形參類型的構造器
    2)向構造器的形參中傳遞一一個對象數組進去,里面包含了構造器中所需的各個參數。
    3)通過Constructor實例化對象

    package com.kuang.demo01; import com.kuang.demo01.User; import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; //動態創建對象,通過反射 public class Test07 {public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException, NoSuchFieldException {//獲得class對象Class c1 = Class.forName("com.kuang.demo01.User");//創建一個對象System.out.println("============================");User user = (User)c1.newInstance();//本質是調用了類的無參構造器System.out.println(user);//通過構造器創建對象System.out.println("============================");Constructor constructor = c1.getDeclaredConstructor(String.class,int.class);User user2 = (User)constructor.newInstance("打爆",22);System.out.println(user2);//通過反射調用普通方法//通過反射獲取一個方法System.out.println("============================");Method setName = c1.getDeclaredMethod("setName",String.class);//invoke:激活的意思//參數:對象,方法的值setName.invoke(user,"韓威");System.out.println(user.getName());System.out.println("============================");//通過反射操作屬性User user3 = (User)c1.newInstance();Field name = c1.getDeclaredField("name");//不能直接操作私有屬性,我們需要關閉程序的安全監測,屬性或方法的setAccessible(true)name.setAccessible(true);name.set(user3,"小寶");System.out.println(user3.getName());} }

    調用指定的方法

    通過反射,調用類中的方法,通過Method類完成。

    ①通過Class類的getMethod(String name,Clas…parameterTypes)方法取得一個Method對象,并設置此方法操作時所需要的參數類型。

    ②之后使用Object invoke(Object obj, Object[] args)進行調用,并向方法中傳遞要設置的obj對象的參數信息。

    [外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-PMHx0vq3-1608789860789)(C:\Users\王東梁\AppData\Roaming\Typora\typora-user-images\image-20201224132215782.png)]

    invoke

    Object invoke(Object obj, Object ... args)
    • Object對應原方法的返回值,若原方法無返回值,此時返回nul)
    • 若原方法若為靜態方法,此時形參0bject obj可為null
    • 若原方法形參列表為空,則Object[] args為null
    • 若原方法聲明為private,則需要在調用此invoke()方法前,顯式調用方法對象的setAccessible(true)方法,將可訪問private的方法。

    setAccessible

    • Method和Field、Constructor對象都有setAccessible()方法。
    • setAccessible作用是啟動和禁用訪問安全檢查的開關。
    • 參數值為true則指示反射的對象在使用時應該取消Java語言訪問檢查。
    • 提高反射的效率。如果代碼中必須用反射,而該句代碼需要頻繁的被調用,那么請設置為true。
    • 使得原本無法訪問的私有成員也可以訪問
    • 參數值為false則指示反射的對象應該實施Java語言訪問檢查

    性能對比分析

    package com.kuang.demo01;import com.kuang.demo01.User;import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method;public class Test09 {public static void main(String[] args) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException {test1();//5mstest2();//4114mstest3();//1483ms}public static void test1(){User user = new User();long start = System.currentTimeMillis();for (int i = 0; i < 1000000000; i++) {user.getName();}long end = System.currentTimeMillis();System.out.println(end-start+"ms");}public static void test2() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {User user = new User();Class c1 = user.getClass();Method getName = c1.getDeclaredMethod("getName",null);long start = System.currentTimeMillis();for (int i = 0; i < 1000000000; i++) {getName.invoke(user,null);}long end = System.currentTimeMillis();System.out.println(end-start+"ms");}public static void test3() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {User user = new User();Class c1 = user.getClass();Method getName = c1.getDeclaredMethod("getName",null);getName.setAccessible(true);long start = System.currentTimeMillis();for (int i = 0; i < 1000000000; i++) {getName.invoke(user,null);}long end = System.currentTimeMillis();System.out.println(end-start+"ms");} }

    反射操作泛型

  • Java采用泛型擦除的機制來引入泛型, Java中的泛型僅僅是給編譯器javac使用的,確保數據的安全性和免去強制類型轉換問題,但是, 一旦編譯完成,所有和泛型有關的類型全部擦除
  • 為了通過反射操作這些類型, Java新增了ParameterizedType , GenericArrayType ,TypeVariable和WildcardType幾種類型來代表不能被歸一-到Class類中的類型但是又和原始類型齊名的類型.
    • ParameterizedType :表示- -種參數化類型,比如Collection
    • GenericArrayType :表示一種元素類型是參數化類型或者類型變量的數組類型
    • TypeVariable :是各種類型變量的公共父接口
    • WildcardType :代表-種通配符類型表達式
  • package com.kuang.demo01;import java.lang.reflect.Method; import java.lang.reflect.ParameterizedType; import java.lang.reflect.Type; import java.util.List; import java.util.Map;public class Test10 {public void test01 (Map<String,User> map, List<User> list){System.out.println("test01");}public Map<String, User> test02(){System.out.println("test02");return null;}public static void main(String[] args) throws NoSuchMethodException {Method method = Test10.class.getMethod("test01",Map.class,List.class);Type[] genericParameterTypes= method.getGenericParameterTypes();for (Type genericParameterType : genericParameterTypes) {System.out.println("參數范型"+genericParameterType);if (genericParameterType instanceof ParameterizedType){Type[] actualTypeAnguments=((ParameterizedType)(ParameterizedType) genericParameterType).getActualTypeArguments();for (Type actualTypeAngument : actualTypeAnguments) {System.out.println("實際參數范型"+actualTypeAngument);}}}Method method1 = Test10.class.getMethod("test02",null);Type getGenericReturnType= method1.getGenericReturnType();if (getGenericReturnType instanceof ParameterizedType) {Type[] actualTypeArguments = ((ParameterizedType) getGenericReturnType).getActualTypeArguments();for (Type actualTypeArgument : actualTypeArguments) {System.out.println("返回值范型" + actualTypeArgument);}}} }

    反射操作注解

  • getAnnotations
  • getAnnotation
  • package com.kuang.demo01; import com.sun.xml.internal.ws.api.ha.StickyFeature; import java.lang.annotation.*; import java.lang.reflect.Field; import java.security.cert.CRLReason; public class Test11 {public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException {Class c1 = Class.forName("com.kuang.demo01.Student2");//通過反射獲取注解Annotation[] annotations = c1.getAnnotations();for (Annotation annotation : annotations) {System.out.println(annotation);//@com.reflection.Table(value=db_student)}//獲得注解中的value值Table table = (Table)c1.getAnnotation(Table.class);String value = table.value();System.out.println(value);//db_student//獲得類指定的注解Field f = c1.getDeclaredField("name");Filed annotation=f.getAnnotation(Filed.class);System.out.println(annotation.columnName());//db_nameSystem.out.println(annotation.length());//3System.out.println(annotation.type());//varchar} } @Table("db_student") class Student2{@Filed(columnName = "db_id",type = "int",length = 10)private int id;@Filed(columnName = "db_age",type = "int",length = 10)private int age;@Filed(columnName = "db_name",type = "varchar",length = 3)private String name;public Student2(){}public Student2(int id, int age, String name) {this.id = id;this.age = age;this.name = name;}public int getId() {return id;}public void setId(int id) {this.id = id;}public int getAge() {return age;}public void setAge(int age) {this.age = age;}public String getName() {return name;}public void setName(String name) {this.name = name;} } //類名的注解 @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @interface Table{String value(); } //字段注解 @Target(ElementType.FIELD) @Retention(RetentionPolicy.RUNTIME) @interface Filed{String columnName();String type();int length(); }

    總結

    以上是生活随笔為你收集整理的JAVA注解和反射(笔记)的全部內容,希望文章能夠幫你解決所遇到的問題。

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