我們知道,當使用反射構造類的實例時,我們常會用到xxx.class.newInstance()這個方法。但是這個方法有一個限制,就是要求類必須有默認的構造函數。但我們在做框架的時候,很難保證要動態構造的類實例,都是有默認構造函數的,那怎麼辦呢?
其實用過C++或者Delphi的都知道,其實構造一個對象,分配內存和調用構造函數實際是兩個不同的步驟。我們要創建一個對象,實際只需要分配它的內存就可以了
那Java中是否有這樣的解決方案呢?答案是:有的!其實在使用xstream做反序列化時,我一直就覺得很神奇,明明我要反序列化的對象是沒有默認構造函數的,它居然也能把它反序列化出來,這到底是怎麼弄的呢?於是我跟蹤了源代碼,就發現了一個Java中很隱蔽的東西,那就是Unsafe類。這個類默認是被隱藏了起來的,甚至連包名都要手動敲(sun.misc.Unsafe),它的用法是這樣的:
Field unsafeField = Unsafe.class.getDeclaredField("theUnsafe");
unsafeField.setAccessible(true);
Unsafe u = (Unsafe) unsafeField.get(null);
MyObject obj = (MyObject) u.allocateInstance(MyObject.class);
我們可以看到,這段代碼,實際就是繞過了構造函數,只分配了對象實例。這樣我們就可以拿着對象實例進行各種操作了。這爲反序列化,還有框架的構建,帶來了極大的方便,不會有“需要默認構造函數”這樣的認爲約束了