java反射中,Class.forName和classloader的區別(代碼說話)

java中class.forName()和classLoader都可用來對類進行加載。
class.forName()前者除了將類的.class文件加載到jvm中之外,還會對類進行解釋,執行類中的static塊。
而classLoader只幹一件事情,就是將.class文件加載到jvm中,不會執行static中的內容,只有在newInstance纔會去執行static塊。
Class.forName(name, initialize, loader)帶參函數也可控制是否加載static塊。並且只有調用了newInstance()方法採用調用構造函數,創建類的對象

看下Class.forName()源碼

	//Class.forName(String className)  這是1.8的源碼public static Class<?> forName(String className) throws ClassNotFoundException {Class<?> caller = Reflection.getCallerClass();return forName0(className, true, ClassLoader.getClassLoader(caller), caller);}	//注意第二個參數,是指Class被loading後是不是必須被初始化。 不初始化就是不執行static的代碼即靜態代碼


然後就是,測試代碼證明上面的結論是OK的,如下:

package com.lxk.Reflect;/** * Created by lxk on 2017/2/21 */public class Line {static {System.out.println("靜態代碼塊執行:loading line");}}


package com.lxk.Reflect;/** * Created by lxk on 2017/2/21 */public class Point {static {System.out.println("靜態代碼塊執行:loading point");}}


package com.lxk.Reflect;/** * Class.forName和classloader的區別 * <p> * Created by lxk on 2017/2/21 */public class ClassloaderAndForNameTest {public static void main(String[] args) {String wholeNameLine = "com.lxk.Reflect.Line";String wholeNamePoint = "com.lxk.Reflect.Point";System.out.println("下面是測試Classloader的效果");testClassloader(wholeNameLine, wholeNamePoint);System.out.println("----------------------------------");System.out.println("下面是測試Class.forName的效果");testForName(wholeNameLine, wholeNamePoint);}/**     * classloader     */private static void testClassloader(String wholeNameLine, String wholeNamePoint) {Class<?> line;Class<?> point;ClassLoader loader = ClassLoader.getSystemClassLoader();try {line = loader.loadClass(wholeNameLine);point = loader.loadClass(wholeNamePoint);//demo = ClassloaderAndForNameTest.class.getClassLoader().loadClass(wholeNamePoint);//這個也是可以的System.out.println("line   " + line.getName());System.out.println("point   " + point.getName());} catch (ClassNotFoundException e) {e.printStackTrace();}}/**     * Class.forName     */private static void testForName(String wholeNameLine, String wholeNamePoint) {try {Class line = Class.forName(wholeNameLine);Class point = Class.forName(wholeNamePoint);System.out.println("line   " + line.getName());System.out.println("point   " + point.getName());} catch (Exception e) {e.printStackTrace();}}}


執行結果如下:



備註:

根據運行結果,可以看到,classloader並沒有執行靜態代碼塊,如開頭的理論所說。

而下面的Class.forName則是夾在完之後,就裏面執行了靜態代碼塊,可以看到,2個類,line和point的靜態代碼塊執行結果是一起的,然後纔是各自的打印結果。

也說明上面理論是OK的。


更新於2017/06/20

因爲看到有小夥伴有疑問,我就把自己以前的代碼拿出來再次測試一遍,發現結果仍然是相同的。

但是,因爲我的Javabean model又經歷了其他的測試,所以,兩個model內部的代碼稍有變化,

然後,還真就測試出來了不一樣的地方。

這估計是其他理論所沒有的。具體看下面的代碼吧。

只是修改了Line的代碼,添加了幾個靜態的方法和變量。

package com.lxk.reflect;/** * Created by lxk on 2017/2/21 */public class Line {static {System.out.println("靜態代碼塊執行:loading line");}public static String s = getString();private static String getString() {System.out.println("給靜態變量賦值的靜態方法執行:loading line");return "ss";}public static void test() {System.out.println("普通靜態方法執行:loading line");}{System.out.println("要是普通的代碼塊呢?");}public Line() {System.out.println("構造方法執行");}}


可以看到,除了原來的簡單的一個靜態代碼塊以外,我又添加了構造方法,靜態方法,以及靜態變量,且,靜態變量被一個靜態方法賦值。

然後,看執行結果。

稍有不同。


除了,靜態代碼塊的執行外,竟然還有一個靜態方法被執行,就是給靜態變量賦值的靜態方法被執行了。

這個估計是以前沒人發現的吧。

所以

上面的結論,就可以進一步的修改啦。

也許,這個執行的也叫,static塊呢。

好吧,

我爲什麼會測試這個呢,是因爲有一次,有遇到說,類加載的問題,詳情看下面鏈接。

Java類的各種成員初始化順序如:父子類繼承時的靜態代碼塊,普通代碼塊,靜態方法,構造方法,等先後順序

這個也是值得看一看的。



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章