Java 反射總結javascript
類裝載器工做機制 php
類裝載器就是尋找類的節碼文件並構造出類在JVM 內部表示對象的組件。在Java 中,
類裝載器把一個類裝入JVM 中,要通過如下步驟:
1.裝載:查找和導入Class 文件;
經過一個類的全限定名來獲取定義此類的二進制字節流.而後將這個字節流所表明的靜態存儲結構轉化爲方法區的運行時數據結構.最後在Java堆中生成一個表明這個類的java.lang.class對像,做爲方法區的數據入口.
2.連接:執行校驗、準備和解析步驟,其中解析步驟是能夠選擇的:
a)校驗:檢查載入Class 文件數據的正確性;
b)準備:給類的靜態變量分配存儲空間;
c)解析:將符號引用轉成直接引用;
3.初始化:對類的靜態變量、靜態代碼塊執行初始化工做。
類裝載工做由ClassLoader 及其子類負責,ClassLoader 是一個重要的Java 運行時系統組件,它負責在運行時查找和裝入Class 字節碼文件。JVM 在運行時會產生三個
ClassLoader:
BootstrapClassLoader
Extension ClassLoader(擴展類裝載器)
Application ClassLoader(系統類裝載器)。
其中,BootstrapClassLoader不是ClassLoader 的子類,它使用C++編寫,所以咱們在Java 中看不到它,BootstrapClassLoader負責裝載JRE 的核心類庫,如JRE 目標下的rt.jar、charsets.jar 等。
Extension ClassLoader 和Application ClassLoader 都是ClassLoader 的子類。其中Extension ClassLoader 負責裝載 JRE 擴展目錄ext 中的JAR 類包;Application 負責裝載Classpath 路徑下的類包。 css
getParent() | 返回該類加載器的父類加載器。 |
loadClass(String name) | 加載名稱爲 name 的類,返回的結果是 java.lang.Class 類的實例。 |
findClass(String name) | 查找名稱爲 name 的類,返回的結果是 java.lang.Class 類的實例。 |
findLoadedClass(String name) | 查找名稱爲 name 的已經被加載過的類,返回的結果是 java.lang.Class 類的實例。 |
defineClass(String name, byte[] b, int off, int len) | 把字節數組 b 中的內容轉換成 Java 類,返回的結果是 java.lang.Class 類的實例。這個方法被聲明爲 final 的。 |
resolveClass(Class<?> c) | 連接指定的 Java 類。 |
public class ClassLoaderTest { public static void main(String[] args) { ClassLoader loader = Thread.currentThread().getContextClassLoader(); System.out.println("current loader:"+loader); System.out.println("parent loader:"+loader.getParent()); System.out.println("grandparent loader:"+loader.getParent(). getParent()); } }
current loader:sun.misc.Launcher$AppClassLoader@131f71a parent loader:sun.misc.Launcher$ExtClassLoader@15601ea //①根裝載器在Java中訪問不到,因此返回null grandparent loader:null
經過以上的輸出信息,咱們知道當前的ClassLoader 是AppClassLoader,父ClassLoader是ExtClassLoader,祖父ClassLoader 是根類裝載器,由於在Java 中沒法得到它的句柄,因此僅返回null。
JVM 裝載類時使用「全盤負責委託機制」,「全盤負責」是指當一個ClassLoader 裝載一個類的時,除非顯式地使用另外一個ClassLoader,該類所依賴及引用的類也由這個ClassLoader 載入;「委託機制」是指先委託父裝載器尋找目標類,只有在找不到的狀況下才從本身的類路徑中查找並裝載目標類。這一點是從安全角度考慮的,試想若是有人編寫了一個惡意的基礎(如java.lang.String)並裝載到JVM 中將會引發多麼可怕的後果。可是因爲有了「全盤負責委託機制」,java.lang.String 永遠是由根裝載器來裝載的,這樣就避免了上述事件的發生。java
獲取當前線程的ClassLoader:程序員
ClassLoader loader = Thread.currentThread().getContextClassLoader(); Class.getClassLoader() ;
實例化Class類對象的三種方式: 編程
Class.forName("Reflect.Demo"); new Demo().getClass(); Demo.class;
Class.forName(className)其實是調用Class.forName(className, true, this.getClass().getClassLoader())。注意第二個參數,是指Class被loading後是否是必須被初始化。
經過Class實例化其餘類的對象 數組
Class<?> demo=Class.forName("Reflect.Person"); Constructor<?> cons[]=demo.getConstructors(); Object object = cons[0].newInstance(args);
經過Class實例化接口 安全
Class<?> intes[]=demo.getInterfaces();
取得其餘類中的父類 ruby
Class<?> superClass=demo.getSuperclass();
調用其餘類中的方法 數據結構
demo = Class.forName("Reflect.Demo"); Method method=demo.getMethod("toString"); method.invoke(demo.newInstance()); Method[] methods = demo.getDeclaredMethods();
經過反射操做屬性:
Field field = demo.getDeclaredField("sex"); field.setAccessible(true); field.set(obj, "男"); Field[] fields = Demo.class.getDeclaredFields(); //類中任何可見性的屬性不包括基類 fields = Demo.class.getFields(); //只能得到public屬性包括基類的
使用數組
Class string = Class.forName("java.lang.String"); Object object= Array.newInstance(string, 10); Array.set(object, 5, "this is a test"); String s = (String) Array.get(arr, 5);
=============================應用==========================
JDK動態代理:
與靜態代理類對照的是動態代理類,動態代理類的字節碼在程序運行時由Java反射機制動態生成,無需程序員手工編寫它的源代碼。動態代理類不只簡化了編程工做,並且提升了軟件系統的可擴展性,由於Java 反射機制能夠生成任意類型的動態代理類。java.lang.reflect 包中的Proxy類和InvocationHandler 接口提供了生成動態代理類的能力。
public class MyHandler implements InvocationHandler { private Object target; public Object bind(Object target) { this.target = target; return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this); } public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("事物開始"); Object result = method.invoke(target, args); System.out.println("事物結束"); return result; } }
Cglib動態代理
JDK的動態代理機制只能代理實現了接口的類,而不能實現接口的類就不能實現JDK的動態代理,cglib是針對類來實現代理的,他的原理是對指定的目標類生成一個子類,並覆蓋其中方法實現加強,但由於採用的是繼承,因此不能對final修飾的類進行代理。
public class MyCglib implements MethodInterceptor { private Object target; public Object getInstance(Object target) { this.target = target; Enhancer enhancer = new Enhancer(); enhancer.setSuperclass(this.target.getClass()); // 回調方法 enhancer.setCallback(this); // 建立代理對象 return enhancer.create(); } @Override // 回調方法 public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable { System.out.println("事物開始"); proxy.invokeSuper(obj, args); System.out.println("事物結束"); return null; } }