Java的世界裏到處存在了對象,有時候換一種眼光每每會給本身帶來與以前大不同的理解。java
一個對象的出現離不開字節碼,拿classforname來說,classforname("...") 就像問你 狗 ,在你腦子裏立馬就出現了狗的樣子,這就是狗的類,拉布拉多就出現拉布拉多狗的類,就相似於一個加載的過程,想要獲得私有的方法,私有的類,好比拉布拉多和其餘種類狗的區別,私有的用setAccessible設置爲true,這樣就能夠調用,這其中加載的過程一眼就看到了父類也會加載進去,這就是類的初始化。編程
而這裏還要說的是classloader是從BootStrapClassLoader開始,到ExtClassLoader再到AppClassLoader,再到本身的ClassLoader。不少人看到這些有的會很明白,一樣的也有不少大頭的,其實拿咱們自身來講,咱們要生存,首先咱們本身得先活着,這就要求咱們有血有肉,各個器官各類無缺,BootStrapClassLoader不就是相似於幹這事的麼,它主要用於加載一些Java自帶的核心類,是不能被替換掉的,由jvm內核實現,只有加載了這些最核心的內容,纔會有後面classloader的存在機會。數組
在有了基本的器官以後,做爲人,咱們要生存還須要一些本能,呼吸,眨眼,條件反射(先天的),這個就相似於ExtClassLoader,其是加載在jre/lib/ext下的jar包,固然,咱們也能夠把本身的jar放到裏面去,經過這個來加載,畢竟咱們的好多先天的條件反射也是慢慢進化來的,是否是很形象jvm
做爲人,咱們能夠學習到不少技能,認識不少事物,每一個人的所見都不同,每一個人都是一個獨立的虛擬機,這裏就談到了AppClassLoader,它加載的是classpath下面的內容,默認狀況都由其加載。ide
固然,凡事總有特殊,用戶自定義的classloader要加載的內容不在上面的classpath範圍內,怎麼加載徹底本身去定義,就像你從未見過某一種東西,你怎麼去知道那是什麼,要不就不打算認識說不知道,要不就給其編個名字安上!函數
上面說了一些class字節碼的加載順序,而後就是對其進行解析校驗,最後是初始化,既然說到了這裏,那就提下,初始化的時候會調用Class對象自身的構造函數,這裏static塊實際上是個坑,當多個線程同時訪問這個類時,必須等static塊執行完,要不會發生阻塞,因此不適合編寫大量的業務尤爲是i/o邏輯業務學習
在classloader源碼裏發現了以下代碼:ui
protected final Class<?> defineClass(String name, byte[] b, int off, int len) throws ClassFormatError { return defineClass(name, b, off, len, null); }
經過傳入byte[]數組就能夠動態的加載Class類,這就牽扯到了字節碼增強。spa
終於和上一篇接着了,只要接觸過Spring都知道,AOP,動態代理,追根究底都是字節碼加強,因此也免不了俗,先說動態代理,看過不少這方面的文章,說說本身的理解,首先,jdk的動態代理,有點相似於專賣店,我拿房地產中介來講可能更好理解一些,一個共同的接口,賣房,房主實現了賣方的接口,房產中介也實現了賣方的接口,而後要有一套賣家賣房的處理流程也就是處理類handler,這個處理類的內部的invoke方法,以下圖所示:線程
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable; }
包含了代理對象,代理方法,方法參數對象,方法內部由被代理的對象來實現,其實就是包含了中介,賣房扯的過程,方法裏面由賣家來實現
java.lang.reflect.Proxy下的newProxyInstance()方法以下所示
@CallerSensitive public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) throws IllegalArgumentException { Objects.requireNonNull(h); final Class<?>[] intfs = interfaces.clone(); final SecurityManager sm = System.getSecurityManager(); if (sm != null) { checkProxyAccess(Reflection.getCallerClass(), loader, intfs); } /* * Look up or generate the designated proxy class. */ Class<?> cl = getProxyClass0(loader, intfs); /* * Invoke its constructor with the designated invocation handler. */ try { if (sm != null) { checkNewProxyPermission(Reflection.getCallerClass(), cl); } final Constructor<?> cons = cl.getConstructor(constructorParams); final InvocationHandler ih = h; if (!Modifier.isPublic(cl.getModifiers())) { AccessController.doPrivileged(new PrivilegedAction<Void>() { public Void run() { cons.setAccessible(true); return null; } }); } return cons.newInstance(new Object[]{h}); } catch (IllegalAccessException|InstantiationException e) { throw new InternalError(e.toString(), e); } catch (InvocationTargetException e) { Throwable t = e.getCause(); if (t instanceof RuntimeException) { throw (RuntimeException) t; } else { throw new InternalError(t.toString(), t); } } catch (NoSuchMethodException e) { throw new InternalError(e.toString(), e); } }
說白了就是想獲得一個代理,就須要賣家的字節碼,賣房的接口,和那個處理類handler,jdk動態代理的很差處也是顯而易見的,必須實現接口,只能調用接口對應的方法,實例的其餘方法沒法訪問,從這點也啓示了咱們面向接口編程和多態的用處。
暫時先敲這麼多吧,剩下的下篇接着說