摘要:裝載類的裝載是通過類加載器完成的,加載器將文件的字節碼文件裝入的方法區,并且在堆區創建描述這個類的對象。通過指定的對象來實例化對象取得父指定的構造類型給傳入參數賦初值實例化反射操作獲得某個類的所有的字段,包括父類。
什么是反射
反射就是在運行時把 Java 類中的各種成分映射成相應的 Java 類(Method、Annotation等),可以動態得獲取所有的屬性以及動態調用任意一個方法。
thisclass A{ public A(){ System.out.println(this.toString() + ";;;;" + this.getClass().getName()); } } class B extends A{ public B() { System.out.println(this.toString() + ";;;;" + super.getClass().getName()); } } public class C extends B{ public C() { System.out.println(this.toString() + ";;;;" + this.getClass().getName()); } public static void main(String[] args) { C c = new C(); } }
輸出結果:
test.C@33b7b32c;;;;test.C
test.C@33b7b32c;;;;test.C
test.C@33b7b32c;;;;test.C
可見this是基于運行時,this的物理內存地址都是C。
Class概念Class類是繼承Type的。
數組屬于被映射為 Class 對象的一個類,具有相同元素類型和維數的數組都共享該 Class 對象。基本的 Java 數據類型和關鍵字 void 也表示為 Class 對象。
Class 沒有公共構造方法。Class
裝載:
類的裝載是通過類加載器完成的,加載器將*.class文件的字節碼文件裝入JVM的方法區,并且在堆區創建描述這個類的java.lang.Class對象。?但是同一個類只會被類裝載器裝載一遍。
連接:
連接就是將已經讀入到內存的類的二進制數據合并到虛擬機的運行時環境中去,分為校驗,準備,解析這3個階段。校驗一般為字節碼合法性驗證,還有語義檢查等;準備就是為靜態變量分配內存空間,并設置默認值;解析指類的二進制數據中的符號引用替換為直接引用(指針)。
Class.forName(ClassName).newInstance() //類實例化,默認用的空參構造函數。
//通過指定的Constructor對象來實例化對象 public?static?void?main(String[]?args)?{?? try?{?? ???????????Class?demo = Class.forName("mypackage.Tests");?//getSuperclass() 取得父class???????? ???????????Class[]?cl = {int.class, int.class};??//指定?Constructor的構造類型 ???????????Constructor?con = demo.getConstructor(cl);?????????????? ???????????Object[]?x = {new?Integer(33),new?Integer(67)};??//給傳入參數賦初值?? ???????????Object?obj = con.newInstance(x);??//實例化?? ???????}?catch?(Exception?e)?{?? ??????????? ???????}?? }?? class?Tests{?? ????public?Tests(int?x, int?y){?? ???????System.out.println(x+"????"+y);?? ????}?? }反射API操作
Class> demo = Class.forName("wangliqiu.test.reflect.MyTest"); Field[] fields = demo.getDeclaredFields(); /* * getFields()獲得某個類的所有public的字段,包括父類。? * getDeclaredFields()獲得某個類的public、private和proteced的字段,但是不包括父類的申明字段。? * 同樣還有getConstructors()和getDeclaredConstructors();getMethods()和getDeclaredMethods()。 */ for (Field field : fields) { field.setAccessible(true);// 強制訪問 // 屬性 System.out.println("Field: " + field.getName()); // 權限修飾符 int mo = field.getModifiers(); System.out.println("Modifier: " + Modifier.toString(mo)); // 屬性類型 Class> classType = field.getType(); System.out.println("Type: " + classType.getName()); } Class> superClass = demo.getSuperclass();// 僅獲取父類 System.out.println("getSuperclass: " + superClass); Type superType = demo.getGenericSuperclass();// 獲取完整的父類(帶有泛型參數) System.out.println("getGenericSuperclass: " + superType); // ParameterizedType參數化類型,即泛型 // getActualTypeArguments獲取類型的參數類型,泛型參數可能有多個 Type[] types = ((ParameterizedType) superType).getActualTypeArguments(); for (Type type : types) { System.out.println("getActualTypeArguments: " + type); } // 可能存在同名但不同參數個數或參數類型的方法,所以getMethod()的方法特征簽名要全面。 Method method = demo.getMethod("justTest", String.class, int.class); method.invoke(demo.newInstance(), "wangliqiu", 20); public void justTest(String name, int age) { System.out.println(name + "====" + age); }ClassLoader
1)Bootstrap ClassLoader?用c++編寫,引導作用。
2)Extension ClassLoader?用java編寫,用來進行擴展類的加載,一般對應的是jrelibext目錄中的類
3)AppClassLoader?用java編寫,加載classpath指定的類,是最常用的加載器。
在加載類時,每個類加載器會先將加載類的任務交給其parent,如果parent找不到,再由自己負責加載。所以加載順序如下圖,若都找不到,會拋出NoClassDefFoundError。
// Bootstrap Loader會加載系統參數sun.boot.class.path指定位置中的文件 System.out.println(System.getProperty("sun.boot.class.path")); // ExtClassLoader會加載系統參數java.ext.dirs指定位置中的文件 System.out.println(System.getProperty("java.ext.dirs")); // AppClassLoader會加載系統參數java.class.path指定位置中的文件,即Classpath路徑 System.out.println(System.getProperty("java.class.path")); /* * java.exe啟動會嘗試找到JRE安裝目錄的jvm.dll,接著啟動JVM ,產生Bootstrap Loader,Bootstrap Loader會加載 * ExtClassLoader,并設定ExtClassLoader的parent為Bootstrap Loader。接著Bootstrap * Loader會加載AppClassLoader,并將AppClassLoader的parent設定為Extended Loader。 */ ClassLoader loader = this.getClass().getClassLoader(); System.out.println(loader.getClass().getName()); // This method will return null if this class was loaded by the bootstrap class loader. ClassLoader loaderloader = loader.getClass().getClassLoader(); System.out.println(loaderloader); ClassLoader parentLoader = loader.getParent(); System.out.println(parentLoader.getClass().getName()); // This method will return null if this class loader"s parent is the bootstrap class loader. ClassLoader GrandLoader = parentLoader.getParent(); System.out.println(GrandLoader);
注:
Class.forName除了將class文件加載到jvm中之外,還會執行類中的static塊。而classLoader只將*.class文件加載到jvm中,不會執行static塊,只有在newInstance才會去執行static塊。Class.forName(name, initialize, loader)帶參函數也可控制是否加載static塊。
類加載:Bootstrap Loader -> ExtClassLoader, Bootstrap Loader -> AppClassLoader?
靜態代碼塊初始化?
鏈接
a) 驗證:是否符合java規范? b) 準備:默認初始值?(如boolean為false,int為0等) c) 解析:符號引用轉為直接引用,解析地址?
初始化?
a) 賦值:類中屬性的初始值? b) 構造:構造函數?@interface
@Retention、@Target、@Documented、@Inherited可以用來修飾注解,是注解的注解,稱為元注解。
@Retention
Retention注解有一個屬性value,是Enum RetentionPolicy枚舉類型,RetentionPolicy有3個值:CLASS? RUNTIME?? SOURCE。
@Retention(RetentionPolicy.SOURCE ) 表示注解的信息只留在源文件中,不參與編譯;
@Retention(RetentionPolicy.CLASS) 表示注解的信息被保留在*.class文件(字節碼文件)中(程序編譯中),但不會被JVM讀取;
@Retention(RetentionPolicy.RUNTIME ) 表示注解的信息被保留在*.class文件(字節碼文件)中,也會被JVM保留在運行時。
例如:
@Retention(RetentionPolicy.SOURCE ) public @interface Override @Retention(RetentionPolicy.SOURCE ) public @interface SuppressWarnings @Retention(RetentionPolicy.RUNTIME ) public @interface Deprecated
@Target
例子:
@Retention(RetentionPolicy.RUNTIME) @interface Test{ String value(); } @Retention(RetentionPolicy.RUNTIME) @interface MyAnnotation{ String hello() default "shanghai"; String world(); //world()沒有默認值,添加注釋MyAnnotation時, world屬性必須輸入參數 int[] array() default { 2, 4, 5, 6 }; Test lannotation() default @Test(value = "ffffd"); Class> style() default String.class; } @MyAnnotation(hello = "beijing", world="class", array={1, 2, 3}, style= int.class) class MyTest{ @MyAnnotation(world = "method", lannotation=@Test(value="baby")) @Deprecated @SuppressWarnings("") public void output(String str, int i){ System.out.println("str:" + str +" int:" + i); } } public class MyReflection{ public static void main(String[] args) throws Exception{ MyAnnotation myClassAnnotation = MyTest.class.getAnnotation(MyAnnotation.class); System.out.println("hello:" + myClassAnnotation.hello() + " world:" + myClassAnnotation.world()); MyAnnotation myMethodAnnotation = method.getAnnotation(MyAnnotation.class); System.out.println("hello:" + myMethodAnnotation.hello() + " world:" + myMethodAnnotation.world() + " @Test.value:" + myMethodAnnotation.lannotation().value() ); Annotation[] annotations = method.getAnnotations(); //獲得方法的所有運行時的注釋 for (Annotation annotation : annotations) { System.out.println(annotation.annotationType().getName()); } } }
輸出:
str:gogo int:9999
hello:beijing world:class
hello:shanghai world:method @Test.value:baby
test.MyAnnotation
java.lang.Deprecated
@SuppressWarnings("")沒有顯示,可見只有運行時的注釋才會執行。
@Documented
由@Documented修飾的注解可以在javadoc中顯示。
@Documented public @interface Column { .... } @Column //@Column將在javadoc中顯示 Public Demo demo { .... }
@Inherited
子類可以繼承父類的帶有@Inherited修飾的注解。
@Inherited public @interface Column { .... } @Column Public class Super { .... } Public class Sub extends Super { .... }
則Sub繼承@Column注解。
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/67269.html
摘要:反射簡介參考官方簡介的話,具有完整的反射,添加了對類接口函數方法和擴展進行反向工程的能力。此外,反射提供了方法來取出函數類和方法中的文檔注釋。 反射簡介 參考官方簡介的話,PHP 5 具有完整的反射 API,添加了對類、接口、函數、方法和擴展進行反向工程的能力。 此外,反射 API 提供了方法來取出函數、類和方法中的文檔注釋。 YII2框架中示例 對于yii2框架,應該都知道di容器,...
摘要:基于反射對象進行查詢模塊反射這里我們不再使用而是使用擴展模塊的獲取所有的對象名獲取表對象進行操作反射關聯關系可以反射并建立表之間的但是建立關聯列的命名為例如關于更多信息請詳細參看官方文檔 示例數據庫下載:http://chinookdatabase.codepl...在SQLALchemy中,我們使用反射技術來獲取相關database schema信息,如tables,views,in...
摘要:簡介是才有的新功能,它是用來導出或提取出關于類方法屬性參數等的詳細信息,包括注釋。 簡介 PHP Reflection API是PHP5才有的新功能,它是用來導出或提取出關于類、方法、屬性、參數等的詳細信息,包括注釋。 class Reflection { } interface Reflector { } class ReflectionException extends Exce...
摘要:效率運行效率使用反射減低程序的運行效率。開發效率由于反射運用到各個框架中,大大加快了開發的效率。 反射的核心就是Class對象,每一個類被jvm加載都會有一個對應的class對象,這個class對象包含了這個類的結構信息,反射就是會通過反射api反復操作這個class對象(屬性,方法,注解,構造器,泛型),但是反射會降低程序的運行效率,比普通方法要慢30倍,通過setAccessble...
近期在維護公司項目的時候遇到一個問題,因為實體類中的 set 方法涉及到了業務邏輯,因此在給對象賦值的過程中不能夠使用 set 方法,為了實現功能,所以采用了反射的機制給對象屬性賦值,借此機會也了解了反射的一些具體用法和使用場景,分以下兩點對反射進行分析: 反射的優勢和劣勢 反射的應用場景 反射的優勢和劣勢 ??個人理解,反射機制實際上就是上帝模式,如果說方法的調用是 Java 正確的打開方式...
摘要:代理和反射的定義調用可常見代替其它目標對象的代理,它虛擬化了目標,所以二者看起來功能一致。代理可攔截引擎內部目標的底層對象操作,這些底層操作被攔截后會觸發響應特定操作的陷阱函數。 代理和反射的定義 調用 new Proxy() 可常見代替其它目標 (target) 對象的代理,它虛擬化了目標,所以二者看起來功能一致。 代理可攔截JS引擎內部目標的底層對象操作,這些底層操作被攔截后會觸發...
閱讀 825·2019-08-30 15:55
閱讀 1406·2019-08-30 13:55
閱讀 1983·2019-08-29 17:13
閱讀 2840·2019-08-29 15:42
閱讀 1331·2019-08-26 14:04
閱讀 1016·2019-08-26 13:31
閱讀 3271·2019-08-26 11:34
閱讀 828·2019-08-23 18:25