假设有这么一个类:
class MyObj { public final int x; public MyObj(int x) { this.x = x; } }和下面的测试代码:
@Test public void gson() { MyObj obj = new Gson().fromJson("{\"x\":1}", MyObj.class); Assert.assertEquals(1, obj.x); }那么GSON是通过什么样的方式创建 MyObj对象的呢?答案可能会出乎你的意料(至少出乎了我的意料)。
经过断点调试或者阅读源代码不难发现,GSON是使用ObjectConstructor来创建对象实例的,这点从代码注释里也能看的出来:
/** * Defines a generic object construction factory. The purpose of this class * is to construct a default instance of a class that can be used for object * navigation while deserialization from its JSON representation. * * @author Inderjeet Singh * @author Joel Leitch */ public interface ObjectConstructor<T> { /** * Returns a new instance. */ public T construct(); }那么ObjectConstructor从何而来呢?答案在 ConstructorConstructor里:
public <T> ObjectConstructor<T> get(TypeToken<T> typeToken) { final Type type = typeToken.getType(); final Class<? super T> rawType = typeToken.getRawType(); // first try an instance creator @SuppressWarnings("unchecked") // types must agree final InstanceCreator<T> typeCreator = (InstanceCreator<T>) instanceCreators.get(type); if (typeCreator != null) { return new ObjectConstructor<T>() { public T construct() { return typeCreator.createInstance(type); } }; } // Next try raw type match for instance creators @SuppressWarnings("unchecked") // types must agree final InstanceCreator<T> rawTypeCreator = (InstanceCreator<T>) instanceCreators.get(rawType); if (rawTypeCreator != null) { return new ObjectConstructor<T>() { public T construct() { return rawTypeCreator.createInstance(type); } }; } ObjectConstructor<T> defaultConstructor = newDefaultConstructor(rawType); if (defaultConstructor != null) { return defaultConstructor; } ObjectConstructor<T> defaultImplementation = newDefaultImplementationConstructor(type, rawType); if (defaultImplementation != null) { return defaultImplementation; } // finally try unsafe return newUnsafeAllocator(type, rawType); }
代码看起来很复杂,但实际上井然有序:
第一和第三种情况暂不考虑,下面来分析第二和第四种情况。
按照前面的分析,这种情况GSON是通过调用默认构造函数来创建对象实例的,让我们证明这一点:
class MyObj { public final int x; public MyObj() { throw new RuntimeException("!!!"); // <--- } }
@Test(expected = RuntimeException.class) // <--- public void gson() { new Gson().fromJson("{\"x\":1}", MyObj.class); }测试通过!
还是通过代码来证明这一点:
class MyObj { public final int x; public MyObj(int x) { // <--- throw new RuntimeException("!!!"); } }
@Test public void gson() { MyObj obj = new Gson().fromJson("{\"x\":1}", MyObj.class); Assert.assertEquals(1, obj.x); }测试通过!
现在让我们一睹UnsafeAllocator的风采:
/** * Do sneaky things to allocate objects without invoking their constructors. * * @author Joel Leitch * @author Jesse Wilson */ public abstract class UnsafeAllocator { public abstract <T> T newInstance(Class<T> c) throws Exception; public static UnsafeAllocator create() { // try JVM // public class Unsafe { // public Object allocateInstance(Class<?> type); // } try { Class<?> unsafeClass = Class.forName("sun.misc.Unsafe"); Field f = unsafeClass.getDeclaredField("theUnsafe"); f.setAccessible(true); final Object unsafe = f.get(null); final Method allocateInstance = unsafeClass.getMethod("allocateInstance", Class.class); return new UnsafeAllocator() { @Override @SuppressWarnings("unchecked") public <T> T newInstance(Class<T> c) throws Exception { return (T) allocateInstance.invoke(unsafe, c); } }; } catch (Exception ignored) { } ... // give up return new UnsafeAllocator() { @Override public <T> T newInstance(Class<T> c) { throw new UnsupportedOperationException("Cannot allocate " + c); } }; } }
去掉反射后,代码看起来大概是这样:
public abstract class UnsafeAllocator { public abstract <T> T newInstance(Class<T> c) throws Exception; public static UnsafeAllocator create() { return new UnsafeAllocator() { @Override @SuppressWarnings("unchecked") public <T> T newInstance(Class<T> c) throws Exception { Unsafe unsafe = sun.misc.Unsafe.theUnsafe; // <-- return (T) unsafe.allocateInstance(c); // <-- } }; } }
答案是,通过反射。详细情况可以参考这个问题,下面我们仅通过代码来证明这一点:
class MyObj { public final int x; public MyObj(int x) { // <--- this.x = x; } }
@Test public void setFinal() throws Exception { MyObj obj = new MyObj(1); Assert.assertEquals(1, obj.x); Field f = obj.getClass().getField("x"); f.setAccessible(true); // <--- f.set(obj, 2); Assert.assertEquals(2, obj.x); }测试通过!
反序列化时,如果一个类没有默认构造函数,那么GSON是通过JDK内部API来创建对象实例的,并且通过反射给final字段赋值。
这种做法通常是很危险的,所以非专业人士请勿效仿!