小白都能學(xué)會的Java注解與反射機(jī)制

      網(wǎng)友投稿 817 2025-04-02

      目錄

      前言

      什么是注解

      內(nèi)置注解

      自定義注解

      Java8 注解

      Java反射機(jī)制

      java.lang.Class 類

      反射操作泛型

      反射操作注解

      性能分析

      前言

      Java注解和反射是很基礎(chǔ)的Java知識了,為何還要講它呢?因?yàn)槲以诿嬖噾?yīng)聘者的過程中,發(fā)現(xiàn)不少面試者很少使用過注解和反射,甚至有人只能說出@Override這一個(gè)注解。我建議大家還是盡量能在開發(fā)中使用注解和反射,有時(shí)候使用它們能讓你事半功倍,簡化代碼提高編碼的效率。很多優(yōu)秀的框架都基本使用了注解和反射,在Spring AOP中,就把注解和反射用得淋漓盡致。

      什么是注解

      Java注解(Annotation)亦叫Java標(biāo)注,是JDK5.0開始引入的一種注釋機(jī)制。 注解可以用在類、接口,方法、變量、參數(shù)以及包等之上。注解可以設(shè)置存在于不同的生命周期中,例如SOURCE(源碼中),CLASS(Class文件中,默認(rèn)是此保留級別),RUNTIME(運(yùn)行期中)。

      注解以@注解名的形式存在于代碼中,Java中內(nèi)置了一些注解,例如@Override,當(dāng)然我們也可以自定義注解。注解也可以有參數(shù),例如@MyAnnotation(value = “陳皮”)。

      @Target(ElementType.METHOD) @Retention(RetentionPolicy.SOURCE) public @interface Override { }

      1

      2

      3

      4

      那注解有什么作用呢?其一是作為一種輔助信息,可以對程序做出一些解釋,例如@Override注解作用于方法上,表示此方法是重寫了父類的方法。其二,注解可以被其他程序讀取,例如編譯器,例如編譯器會對被@Override注解的方法檢測判斷方法名和參數(shù)等是否與父類相同,否則會編譯報(bào)錯(cuò);而且在運(yùn)行期可以通過反射機(jī)制訪問某些注解信息。

      內(nèi)置注解

      Java中有10個(gè)內(nèi)置注解,其中6個(gè)注解是作用在代碼上的,4個(gè)注解是負(fù)責(zé)注解其他注解的(即元注解),元注解提供對其他注解的類型說明。

      自定義注解

      使用@interface關(guān)鍵字自定義注解,其實(shí)底層就是定義了一個(gè)接口,而且自動繼承java.lang.annotation.Annotation接口。

      我們自定義一個(gè)注解如下:

      @Target(ElementType.METHOD) @Retention(RetentionPolicy.SOURCE) public @interface MyAnnotation { String value(); }

      1

      2

      3

      4

      5

      我們使用命令javap反編譯我們定義的MyAnnotation注解的class文件,結(jié)果顯示如下。雖然注解隱式繼承了Annotation接口,但是Java不允許我們顯示通過extends關(guān)鍵字繼承Annotation接口甚至其他接口,否則編譯報(bào)錯(cuò)。

      D:\>javap MyAnnotation.class Compiled from "MyAnnotation.java" public interface com.nobody.MyAnnotation extends java.lang.annotation.Annotation { public abstract java.lang.String value(); }

      1

      2

      3

      4

      5

      注解的定義內(nèi)容如下:

      格式為public @interface 注解名 {定義內(nèi)容}

      內(nèi)部的每一個(gè)方法實(shí)際是聲明了一個(gè)參數(shù),方法的名稱就是參數(shù)的名稱。

      返回值類型就是參數(shù)的類型,而且返回值類型只能是基本類型(int,float,long,short,boolean,byte,double,char),Class,String,enum,Annotation以及上述類型的數(shù)組形式。

      如果定義了參數(shù),可通過default關(guān)鍵字聲明參數(shù)的默認(rèn)值,若不指定默認(rèn)值,使用時(shí)就一定要顯示賦值,而且不允許使用null值,一般會使用空字符串或者0。

      如果只有一個(gè)參數(shù),一般參數(shù)名為value,因?yàn)槭褂米⒔鈺r(shí),賦值可以不顯示寫出參數(shù)名,直接寫參數(shù)值。

      import java.lang.annotation.*; /** * @Description 自定義注解 * @Author Mr.nobody * @Date 2021/3/30 * @Version 1.0 */ @Target(ElementType.METHOD) // 此注解只能用在方法上。 @Retention(RetentionPolicy.RUNTIME) // 此注解保存在運(yùn)行時(shí)期,可以通過反射訪問。 @Inherited // 說明子類可以繼承此類的此注解。 @Documented // 此注解包含在用戶文檔中。 public @interface CustomAnnotation { String value(); // 使用時(shí)需要顯示賦值 int id() default 0; // 有默認(rèn)值,使用時(shí)可以不賦值 }

      1

      2

      3

      4

      5

      6

      7

      8

      9

      10

      11

      12

      13

      小白都能學(xué)會的Java注解與反射機(jī)制

      14

      15

      16

      /** * @Description 測試注解 * @Author Mr.nobody * @Date 2021/3/30 * @Version 1.0 */ public class TestAnnotation { // @CustomAnnotation(value = "test") 只能注解在方法上,這里會報(bào)錯(cuò) private String str = "Hello World!"; @CustomAnnotation(value = "test") public static void main(String[] args) { System.out.println(str); } }

      1

      2

      3

      4

      5

      6

      7

      8

      9

      10

      11

      12

      13

      14

      15

      16

      Java8 注解

      在這里講解下Java8之后的幾個(gè)注解和新特性,其中一個(gè)注解是@FunctionalInterface,它作用在接口上,標(biāo)識是一個(gè)函數(shù)式接口,即只有有一個(gè)抽象方法,但是可以有默認(rèn)方法。

      @FunctionalInterface public interface Callback { public R call(P param); }

      1

      2

      3

      4

      5

      還有一個(gè)注解是@Repeatable,它允許在同一個(gè)位置使用多個(gè)相同的注解,而在Java8之前是不允許的。

      @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Repeatable(OperTypes.class) public @interface OperType { String[] value(); }

      1

      2

      3

      4

      5

      6

      // 可以理解@OperTypes注解作為接收同一個(gè)類型上重復(fù)@OperType注解的容器 @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) public @interface OperTypes { OperType[] value(); }

      1

      2

      3

      4

      5

      6

      @OperType("add") @OperType("update") public class MyClass { }

      1

      2

      3

      4

      5

      注意,對于重復(fù)注解,不能再通過clz.getAnnotation(Class annotationClass)方法來獲取重復(fù)注解,Java8之后,提供了新的方法來獲取重復(fù)注解,即clz.getAnnotationsByType(Class annotationClass)方法。

      package com.nobody; import java.lang.annotation.Annotation; /** * @Description * @Author Mr.nobody * @Date 2021/3/31 * @Version 1.0 */ @OperType("add") @OperType("update") public class MyClass { public static void main(String[] args) { Class clz = MyClass.class; Annotation[] annotations = clz.getAnnotations(); for (Annotation annotation : annotations) { System.out.println(annotation.toString()); } OperType operType = clz.getAnnotation(OperType.class); System.out.println(operType); OperType[] operTypes = clz.getAnnotationsByType(OperType.class); for (OperType type : operTypes) { System.out.println(type.toString()); } } } // 輸出結(jié)果為 @com.nobody.OperTypes(value=[@com.nobody.OperType(value=[add]), @com.nobody.OperType(value=[update])]) null @com.nobody.OperType(value=[add]) @com.nobody.OperType(value=[update])

      1

      2

      3

      4

      5

      6

      7

      8

      9

      10

      11

      12

      13

      14

      15

      16

      17

      18

      19

      20

      21

      22

      23

      24

      25

      26

      27

      28

      29

      30

      31

      32

      33

      34

      35

      36

      37

      在Java8中,ElementType枚舉新增了兩個(gè)枚舉成員,分別為TYPE_PARAMETER和TYPE_USE,TYPE_PARAMETER標(biāo)識注解可以作用于類型參數(shù),TYPE_USE標(biāo)識注解可以作用于標(biāo)注任意類型(除了Class)。

      Java反射機(jī)制

      我們先了解下什么是靜態(tài)語言和動態(tài)語言。動態(tài)語言是指在運(yùn)行時(shí)可以改變其自身結(jié)構(gòu)的語言。例如新的函數(shù),對象,甚至代碼可以被引進(jìn),已有的函數(shù)可以被刪除或者結(jié)構(gòu)上的一些變化。簡單說即是在運(yùn)行時(shí)代碼可以根據(jù)某些條件改變自身結(jié)構(gòu)。動態(tài)語言主要有C#,Object-C,JavaScript,PHP,Python等。靜態(tài)語言是指運(yùn)行時(shí)結(jié)構(gòu)不可改變的語言,例如Java,C,C++等。

      Java不是動態(tài)語言,但是它可以稱為準(zhǔn)動態(tài)語言,因?yàn)镴ava可以利用反射機(jī)制獲得類似動態(tài)語言的特性,Java的動態(tài)性讓它在編程時(shí)更加靈活。

      反射機(jī)制允許程序在執(zhí)行期借助于Reflection API取得任何類的內(nèi)部信息,并能直接操作任意對象的內(nèi)部屬性以及方法等。類在被加載完之后,會在堆內(nèi)存的方法區(qū)中生成一個(gè)Class類型的對象,一個(gè)類只有一個(gè)Class對象,這個(gè)對象包含了類的結(jié)構(gòu)信息。我們可以通過這個(gè)對象看到類的結(jié)構(gòu)。

      比如我們可以通過Class clz = Class.forName("java.lang.String");獲得String類的Class對象。我們知道每個(gè)類都隱式繼承Object類,Object類有個(gè)getClass()方法也能獲取Class對象。

      Java反射機(jī)制提供的功能

      在運(yùn)行時(shí)判斷任意一個(gè)對象所屬的類

      在運(yùn)行時(shí)構(gòu)造任意一個(gè)類的對象

      在運(yùn)行時(shí)判斷任意一個(gè)類具有的成員變量和方法

      在運(yùn)行時(shí)獲取泛型信息

      在運(yùn)行時(shí)調(diào)用任意一個(gè)對象的成員變量和方法

      在運(yùn)行時(shí)獲取注解

      生成動態(tài)代理

      Java反射機(jī)制的優(yōu)缺點(diǎn)

      優(yōu)點(diǎn):實(shí)現(xiàn)動態(tài)創(chuàng)建對象和編譯,有更加的靈活性。

      缺點(diǎn):對性能有影響。使用反射其實(shí)是一種解釋操作,即告訴JVM我們想要做什么,然后它滿足我們的要求,所以總是慢于直接執(zhí)行相同的操作。

      Java反射相關(guān)的主要API

      java.lang.Class:代表一個(gè)類

      java.lang.reflect.Method:代表類的方法

      java.lang.reflect.Field:代表類的成員變量

      java.lang.reflect.Constructor:代表類的構(gòu)造器

      我們知道在運(yùn)行時(shí)通過反射可以準(zhǔn)確獲取到注解信息,其實(shí)以上類(Class,Method,F(xiàn)ield,Constructor等)都直接或間接實(shí)現(xiàn)了AnnotatedElement接口,并實(shí)現(xiàn)了它定義的方法,AnnotatedElement接口的作用主要用于表示正在JVM中運(yùn)行的程序中已使用注解的元素,通過該接口提供的方法可以獲取到注解信息。

      java.lang.Class 類

      在Java反射中,最重要的是Class這個(gè)類了。Class本身也是一個(gè)類。當(dāng)程序想要使用某個(gè)類時(shí),如果此類還未被加載到內(nèi)存中,首先會將類的class文件字節(jié)碼加載到內(nèi)存中,并將這些靜態(tài)數(shù)據(jù)轉(zhuǎn)換為方法區(qū)的運(yùn)行時(shí)數(shù)據(jù)結(jié)構(gòu),然后生成一個(gè)Class類型的對象(Class對象只能由系統(tǒng)創(chuàng)建),一個(gè)類只有一個(gè)Class對象,這個(gè)對象包含了類的結(jié)構(gòu)信息。我們可以通過這個(gè)對象看到類的結(jié)構(gòu)。每個(gè)類的實(shí)例都會記得自己是由哪個(gè)Class實(shí)例所生成的。

      通過Class對象可以知道某個(gè)類的屬性,方法,構(gòu)造器,注解,以及實(shí)現(xiàn)了哪些接口等信息。注意,只有class,interface,enum,annotation,primitive type,void,[] 等才有Class對象。

      package com.nobody; import java.lang.annotation.ElementType; import java.util.Map; public class TestClass { public static void main(String[] args) { // 類 Class myClassClass = MyClass.class; // 接口 Class mapClass = Map.class; // 枚舉 Class elementTypeClass = ElementType.class; // 注解 Class overrideClass = Override.class; // 原生類型 Class integerClass = Integer.class; // 空類型 Class voidClass = void.class; // 一維數(shù)組 Class aClass = String[].class; // 二維數(shù)組 Class aClass1 = String[][].class; // Class類也有Class對象 Class classClass = Class.class; System.out.println(myClassClass); System.out.println(mapClass); System.out.println(elementTypeClass); System.out.println(overrideClass); System.out.println(integerClass); System.out.println(voidClass); System.out.println(aClass); System.out.println(aClass1); System.out.println(classClass); } } // 輸出結(jié)果 class com.nobody.MyClass interface java.util.Map class java.lang.annotation.ElementType interface java.lang.Override class java.lang.Integer void class [Ljava.lang.String; class [[Ljava.lang.String; class java.lang.Class

      1

      2

      3

      4

      5

      6

      7

      8

      9

      10

      11

      12

      13

      14

      15

      16

      17

      18

      19

      20

      21

      22

      23

      24

      25

      26

      27

      28

      29

      30

      31

      32

      33

      34

      35

      36

      37

      38

      39

      40

      41

      42

      43

      44

      45

      46

      47

      48

      49

      50

      獲取Class對象的方法

      如果知道具體的類,可通過類的class屬性獲取,這種方法最安全可靠并且性能最高。Class clz = User.class;

      通過類的實(shí)例的getClass()方法獲取。Class clz = user.getClass();

      如果知道一個(gè)類的全限定類名,并且在類路徑下,可通過Class.forName()方法獲取,但是可能會拋出ClassNotFoundException。Class clz = Class.forName("com.nobody.User");

      內(nèi)置的基本數(shù)據(jù)類型可以直接通過類名.Type獲取。Class clz = Integer.TYPE;

      通過類加載器ClassLoader獲取

      Class類的常用方法

      public static Class forName(String className):創(chuàng)建一個(gè)指定全限定類名的Class對象

      public T newInstance():調(diào)用Class對象所代表的類的無參構(gòu)造方法,創(chuàng)建一個(gè)實(shí)例

      public String getName():返回Class對象所代表的類的全限定名稱。

      public String getSimpleName():返回Class對象所代表的類的簡單名稱。

      public native Class getSuperclass():返回Class對象所代表的類的父類的Class對象,這是一個(gè)本地方法

      public Class[] getInterfaces():返回Class對象的接口

      public Field[] getFields():返回Class對象所代表的實(shí)體的public屬性Field對象數(shù)組

      public Field[] getDeclaredFields():返回Class對象所代表的實(shí)體的所有屬性Field對象數(shù)組

      public Field getDeclaredField(String name):獲取指定屬性名的Field對象

      public Method[] getDeclaredMethods():返回Class對象所代表的實(shí)體的所有Method對象數(shù)組

      public Method getDeclaredMethod(String name, Class… parameterTypes):返回指定名稱和參數(shù)類型的Method對象

      myClassClass.getDeclaredConstructors();:返回所有Constructor對象的數(shù)組

      public ClassLoader getClassLoader():返回當(dāng)前類的類加載器

      在反射中經(jīng)常會使用到Method的invoke方法,即public Object invoke(Object obj, Object... args),我們簡單說明下:

      第一個(gè)Object對應(yīng)原方法的返回值,若原方法沒有返回值,則返回null。

      第二個(gè)Object對象對應(yīng)調(diào)用方法的實(shí)例,若原方法為靜態(tài)方法,則參數(shù)obj可為null。

      第二個(gè)Object對應(yīng)若原方法形參列表,若參數(shù)為空,則參數(shù)args為null。

      若原方法聲明為private修飾,則調(diào)用invoke方法前,需要顯示調(diào)用方法對象的method.setAccessible(true)方法,才可訪問private方法。

      反射操作泛型

      泛型是JDK 1.5的一項(xiàng)新特性,它的本質(zhì)是參數(shù)化類型(Parameterized Type)的應(yīng)用,也就是說所操作的數(shù)據(jù)類型被指定為一個(gè)參數(shù),在用到的時(shí)候再指定具體的類型。這種參數(shù)類型可以用在類、接口和方法的創(chuàng)建中,分別稱為泛型類、泛型接口和泛型方法。

      在Java中,采用泛型擦除的機(jī)制來引入泛型,泛型能編譯器使用javac時(shí)確保數(shù)據(jù)的安全性和免去強(qiáng)制類型轉(zhuǎn)換問題,泛型提供了編譯時(shí)類型安全檢測機(jī)制,該機(jī)制允許程序員在編譯時(shí)檢測到非法的類型。并且一旦編譯完成,所有和泛型有關(guān)的類型會被全部擦除。

      Java新增了ParameterizedType,GenericArrayType,TypeVariable和WildcardType等幾種類型,能讓我們通過反射操作這些類型。

      ParameterizedType:表示一種參數(shù)化類型,比如Collection

      GenericArrayType:表示種元素類型是參數(shù)化類型或者類型變量的數(shù)組類型

      TypeVariable:是各種類型變量的公共父接口

      WildcardType:代表種通配符類型表達(dá)式

      package com.nobody; import java.lang.reflect.Method; import java.lang.reflect.ParameterizedType; import java.lang.reflect.Type; import java.util.Map; public class TestReflectGenerics { public Map test(Map map, Person person) { return null; } public static void main(String[] args) throws NoSuchMethodException { // 獲取test方法對象 Method test = TestReflectGenerics.class.getDeclaredMethod("test", Map.class, Person.class); // 獲取方法test的參數(shù)類型 Type[] genericParameterTypes = test.getGenericParameterTypes(); for (Type genericParameterType : genericParameterTypes) { System.out.println("方法參數(shù)類型:" + genericParameterType); // 如果參數(shù)類型等于參數(shù)化類型 if (genericParameterType instanceof ParameterizedType) { // 獲得真實(shí)參數(shù)類型 Type[] actualTypeArguments = ((ParameterizedType) genericParameterType).getActualTypeArguments(); for (Type actualTypeArgument : actualTypeArguments) { System.out.println(" " + actualTypeArgument); } } } // 獲取方法test的返回值類型 Type genericReturnType = test.getGenericReturnType(); System.out.println("返回值類型:" + genericReturnType); // 如果參數(shù)類型等于參數(shù)化類型 if (genericReturnType instanceof ParameterizedType) { // 獲得真實(shí)參數(shù)類型 Type[] actualTypeArguments = ((ParameterizedType) genericReturnType).getActualTypeArguments(); for (Type actualTypeArgument : actualTypeArguments) { System.out.println(" " + actualTypeArgument); } } } } class Person {} // 輸出結(jié)果 方法參數(shù)類型:java.util.Map class java.lang.String class java.lang.Integer 方法參數(shù)類型:class com.nobody.Person 返回值類型:java.util.Map class java.lang.String class com.nobody.Person

      1

      2

      3

      4

      5

      6

      7

      8

      9

      10

      11

      12

      13

      14

      15

      16

      17

      18

      19

      20

      21

      22

      23

      24

      25

      26

      27

      28

      29

      30

      31

      32

      33

      34

      35

      36

      37

      38

      39

      40

      41

      42

      43

      44

      45

      46

      47

      48

      49

      50

      51

      52

      53

      54

      55

      56

      57

      反射操作注解

      在Java運(yùn)行時(shí),通過反射獲取代碼中的注解是比較常用的手段了,獲取到了注解之后,就能知道注解的所有信息了,然后根據(jù)信息進(jìn)行相應(yīng)的操作。下面通過一個(gè)例子,獲取類和屬性的注解,解析映射為數(shù)據(jù)庫中的表信息。

      package com.nobody; import java.lang.annotation.*; public class AnalysisAnnotation { public static void main(String[] args) throws Exception { Class aClass = Class.forName("com.nobody.Book"); // 獲取類的指定注解,并且獲取注解的值 Table annotation = aClass.getAnnotation(Table.class); String value = annotation.value(); System.out.println("Book類映射的數(shù)據(jù)庫表名:" + value); java.lang.reflect.Field bookName = aClass.getDeclaredField("bookName"); TableField annotation1 = bookName.getAnnotation(TableField.class); System.out.println("bookName屬性映射的數(shù)據(jù)庫字段屬性 - 列名:" + annotation1.colName() + ",類型:" + annotation1.type() + ",長度:" + annotation1.length()); java.lang.reflect.Field price = aClass.getDeclaredField("price"); TableField annotation2 = price.getAnnotation(TableField.class); System.out.println("price屬性映射的數(shù)據(jù)庫字段屬性 - 列名:" + annotation2.colName() + ",類型:" + annotation2.type() + ",長度:" + annotation2.length()); } } // 作用于類的注解,用于解析表數(shù)據(jù) @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @interface Table { // 表名 String value(); } // 作用于字段,用于解析表列 @Target(ElementType.FIELD) @Retention(RetentionPolicy.RUNTIME) @interface TableField { // 列名 String colName(); // 列類型 String type(); // 長度 int length(); } @Table("t_book") class Book { @TableField(colName = "name", type = "varchar", length = 15) String bookName; @TableField(colName = "price", type = "int", length = 10) int price; } // 輸出結(jié)果 Book類映射的數(shù)據(jù)庫表名:t_book bookName屬性映射的數(shù)據(jù)庫字段屬性 - 列名:name,類型:varchar,長度:15 price屬性映射的數(shù)據(jù)庫字段屬性 - 列名:price,類型:int,長度:10

      1

      2

      3

      4

      5

      6

      7

      8

      9

      10

      11

      12

      13

      14

      15

      16

      17

      18

      19

      20

      21

      22

      23

      24

      25

      26

      27

      28

      29

      30

      31

      32

      33

      34

      35

      36

      37

      38

      39

      40

      41

      42

      43

      44

      45

      46

      47

      48

      49

      50

      51

      52

      53

      54

      55

      56

      57

      58

      性能分析

      前面我們說過,反射對性能有一定影響。因?yàn)榉瓷涫且环N解釋操作,它總是慢于直接執(zhí)行相同的操作。而且Method,F(xiàn)ield,Constructor都有setAccessible()方法,它的作用是開啟或禁用訪問安全檢查。如果我們程序代碼中用到了反射,而且此代碼被頻繁調(diào)用,為了提高反射效率,則最好禁用訪問安全檢查,即設(shè)置為true。

      package com.nobody; import java.lang.reflect.Method; public class TestReflectSpeed { // 10億次 private static int times = 1000000000; public static void main(String[] args) throws Exception { test01(); test02(); test03(); } public static void test01() { Teacher t = new Teacher(); long start = System.currentTimeMillis(); for (int i = 0; i < times; i++) { t.getName(); } long end = System.currentTimeMillis(); System.out.println("普通方式執(zhí)行10億次消耗:" + (end - start) + "ms"); } public static void test02() throws Exception { Teacher teacher = new Teacher(); Class aClass = Class.forName("com.nobody.Teacher"); Method getName = aClass.getDeclaredMethod("getName"); long start = System.currentTimeMillis(); for (int i = 0; i < times; i++) { getName.invoke(teacher); } long end = System.currentTimeMillis(); System.out.println("反射方式執(zhí)行10億次消耗:" + (end - start) + "ms"); } public static void test03() throws Exception { Teacher teacher = new Teacher(); Class aClass = Class.forName("com.nobody.Teacher"); Method getName = aClass.getDeclaredMethod("getName"); getName.setAccessible(true); long start = System.currentTimeMillis(); for (int i = 0; i < times; i++) { getName.invoke(teacher); } long end = System.currentTimeMillis(); System.out.println("關(guān)閉安全檢查反射方式執(zhí)行10億次消耗:" + (end - start) + "ms"); } } class Teacher { private String name; public String getName() { return name; } public void setName(String name) { this.name = name; } } //輸出結(jié)果 普通方式執(zhí)行10億次消耗:13ms 反射方式執(zhí)行10億次消耗:20141ms 關(guān)閉安全檢查反射方式執(zhí)行10億次消耗:8233ms

      1

      2

      3

      4

      5

      6

      7

      8

      9

      10

      11

      12

      13

      14

      15

      16

      17

      18

      19

      20

      21

      22

      23

      24

      25

      26

      27

      28

      29

      30

      31

      32

      33

      34

      35

      36

      37

      38

      39

      40

      41

      42

      43

      44

      45

      46

      47

      48

      49

      50

      51

      52

      53

      54

      55

      56

      57

      58

      59

      60

      61

      62

      63

      64

      65

      66

      67

      68

      69

      70

      通過實(shí)驗(yàn)可知,反射比直接執(zhí)行相同的方法慢了很多,特別是當(dāng)反射的操作被頻繁調(diào)用時(shí)效果更明顯,當(dāng)然通過關(guān)閉安全檢查可以提高一些速度。所以,放射也不應(yīng)該泛濫成災(zāi)的,而是適度使用才能發(fā)揮最大作用。

      Java 數(shù)據(jù)結(jié)構(gòu)

      版權(quán)聲明:本文內(nèi)容由網(wǎng)絡(luò)用戶投稿,版權(quán)歸原作者所有,本站不擁有其著作權(quán),亦不承擔(dān)相應(yīng)法律責(zé)任。如果您發(fā)現(xiàn)本站中有涉嫌抄襲或描述失實(shí)的內(nèi)容,請聯(lián)系我們jiasou666@gmail.com 處理,核實(shí)后本網(wǎng)站將在24小時(shí)內(nèi)刪除侵權(quán)內(nèi)容。

      版權(quán)聲明:本文內(nèi)容由網(wǎng)絡(luò)用戶投稿,版權(quán)歸原作者所有,本站不擁有其著作權(quán),亦不承擔(dān)相應(yīng)法律責(zé)任。如果您發(fā)現(xiàn)本站中有涉嫌抄襲或描述失實(shí)的內(nèi)容,請聯(lián)系我們jiasou666@gmail.com 處理,核實(shí)后本網(wǎng)站將在24小時(shí)內(nèi)刪除侵權(quán)內(nèi)容。

      上一篇:wps表格怎樣畫斜線(wps表格怎樣畫斜線打字)
      下一篇:word如何使用函數(shù)統(tǒng)計(jì)表格的數(shù)據(jù)(word文檔表格如何制作統(tǒng)計(jì)表格)
      相關(guān)文章
      亚洲欧洲在线播放| 亚洲天堂男人影院| 亚洲精品一区二区三区四区乱码| 中文亚洲AV片在线观看不卡| 国产成人精品日本亚洲18图| 久久精品国产亚洲AV高清热| 亚洲精品无码久久一线| 亚洲熟女少妇一区二区| 亚洲成人影院在线观看| 国产精品亚洲综合天堂夜夜| 国产精品亚洲а∨天堂2021| 久久精品熟女亚洲av麻豆| 色综合久久精品亚洲国产| 久久亚洲精品成人无码| 亚洲五月丁香综合视频| 亚洲欧洲日韩极速播放| 亚洲精品无码成人| 亚洲AV综合永久无码精品天堂| 欧美亚洲国产SUV| 亚洲欧洲AV无码专区| 亚洲av日韩专区在线观看| 美女视频黄免费亚洲| 亚洲avav天堂av在线网毛片| 国产成人亚洲综合无| 无码专区一va亚洲v专区在线| 亚洲色婷婷综合开心网| 亚洲综合亚洲综合网成人| 亚洲日韩乱码中文无码蜜桃臀网站| 亚洲国产精品无码专区影院| 亚洲国产精品VA在线观看麻豆| 久久亚洲美女精品国产精品| 亚洲国产成+人+综合| 亚洲色欲色欲www| 亚洲国产精品无码第一区二区三区| 国产成人精品久久亚洲高清不卡| 五月婷婷亚洲综合| 亚洲精品无码午夜福利中文字幕| 亚洲色成人网站WWW永久| 亚洲AV人无码综合在线观看 | 久久久久亚洲AV成人无码网站| 亚洲AV无码国产丝袜在线观看 |