乡下人产国偷v产偷v自拍,国产午夜片在线观看,婷婷成人亚洲综合国产麻豆,久久综合给合久久狠狠狠9

  • <output id="e9wm2"></output>
    <s id="e9wm2"><nobr id="e9wm2"><ins id="e9wm2"></ins></nobr></s>

    • 分享

      GSON使用筆記(2)

       王慶峰 2015-06-19

      從一個問題開始

      假設有這么一個類:

      1. class MyObj {  
      2.       
      3.     public final int x;  
      4.       
      5.     public MyObj(int x) {  
      6.         this.x = x;  
      7.     }  
      8.       
      9. }  
      和下面的測試代碼:
      1. @Test  
      2. public void gson() {  
      3.     MyObj obj = new Gson().fromJson("{\"x\":1}", MyObj.class);  
      4.     Assert.assertEquals(1, obj.x);  
      5. }  
      那么GSON是通過什么樣的方式創(chuàng)建MyObj對象的呢?答案可能會出乎你的意料(至少出乎了我的意料)。


      InstanceCreator和ObjectConstructor

      經過斷點調試或者閱讀源代碼不難發(fā)現(xiàn),GSON是使用ObjectConstructor來創(chuàng)建對象實例的,這點從代碼注釋里也能看的出來:

      1. /** 
      2.  * Defines a generic object construction factory.  The purpose of this class 
      3.  * is to construct a default instance of a class that can be used for object 
      4.  * navigation while deserialization from its JSON representation. 
      5.  * 
      6.  * @author Inderjeet Singh 
      7.  * @author Joel Leitch 
      8.  */  
      9. public interface ObjectConstructor<T> {  
      10.   
      11.   /** 
      12.    * Returns a new instance. 
      13.    */  
      14.   public T construct();  
      15. }  
      那么ObjectConstructor從何而來呢?答案在ConstructorConstructor里:
      1. public <T> ObjectConstructor<T> get(TypeToken<T> typeToken) {  
      2.   final Type type = typeToken.getType();  
      3.   final Class<? super T> rawType = typeToken.getRawType();  
      4.   
      5.   // first try an instance creator  
      6.   
      7.   @SuppressWarnings("unchecked"// types must agree  
      8.   final InstanceCreator<T> typeCreator = (InstanceCreator<T>) instanceCreators.get(type);  
      9.   if (typeCreator != null) {  
      10.     return new ObjectConstructor<T>() {  
      11.       public T construct() {  
      12.         return typeCreator.createInstance(type);  
      13.       }  
      14.     };  
      15.   }  
      16.   
      17.   // Next try raw type match for instance creators  
      18.   @SuppressWarnings("unchecked"// types must agree  
      19.   final InstanceCreator<T> rawTypeCreator =  
      20.       (InstanceCreator<T>) instanceCreators.get(rawType);  
      21.   if (rawTypeCreator != null) {  
      22.     return new ObjectConstructor<T>() {  
      23.       public T construct() {  
      24.         return rawTypeCreator.createInstance(type);  
      25.       }  
      26.     };  
      27.   }  
      28.   
      29.   ObjectConstructor<T> defaultConstructor = newDefaultConstructor(rawType);  
      30.   if (defaultConstructor != null) {  
      31.     return defaultConstructor;  
      32.   }  
      33.   
      34.   ObjectConstructor<T> defaultImplementation = newDefaultImplementationConstructor(type, rawType);  
      35.   if (defaultImplementation != null) {  
      36.     return defaultImplementation;  
      37.   }  
      38.   
      39.   // finally try unsafe  
      40.   return newUnsafeAllocator(type, rawType);  
      41. }  

      代碼看起來很復雜,但實際上井然有序:

      1. 如果我們(通過GsonBuilder)注冊過InstanceCreator,則交給InstanceCreator來創(chuàng)建實例
      2. 如果類有默認構造函數(shù),則通過反射調用默認構造函數(shù)創(chuàng)建實例
      3. 如果想要創(chuàng)建ListMap等接口的實例,則走這里
      4. 否則交給神秘的UnsafeAllocator來收場

      第一和第三種情況暫不考慮,下面來分析第二和第四種情況。


      有默認構造函數(shù)的情況

      按照前面的分析,這種情況GSON是通過調用默認構造函數(shù)來創(chuàng)建對象實例的,讓我們證明這一點:

      1. class MyObj {  
      2.       
      3.     public final int x;  
      4.       
      5.     public MyObj() {  
      6.         throw new RuntimeException("!!!"); // <---  
      7.     }  
      8.       
      9. }  
      1. @Test(expected = RuntimeException.class// <---  
      2. public void gson() {  
      3.     new Gson().fromJson("{\"x\":1}", MyObj.class);  
      4. }  
      測試通過!


      沒有默認構造函數(shù)的情況

      還是通過代碼來證明這一點:

      1. class MyObj {  
      2.       
      3.     public final int x;  
      4.       
      5.     public MyObj(int x) { // <---  
      6.         throw new RuntimeException("!!!");  
      7.     }  
      8.       
      9. }  
      1. @Test  
      2. public void gson() {  
      3.     MyObj obj = new Gson().fromJson("{\"x\":1}", MyObj.class);  
      4.     Assert.assertEquals(1, obj.x);  
      5. }  
      測試通過!

      UnsafeAllocator

      現(xiàn)在讓我們一睹UnsafeAllocator的風采:

      1. /** 
      2.  * Do sneaky things to allocate objects without invoking their constructors. 
      3.  * 
      4.  * @author Joel Leitch 
      5.  * @author Jesse Wilson 
      6.  */  
      7. public abstract class UnsafeAllocator {  
      8.   public abstract <T> T newInstance(Class<T> c) throws Exception;  
      9.   
      10.   public static UnsafeAllocator create() {  
      11.     // try JVM  
      12.     // public class Unsafe {  
      13.     //   public Object allocateInstance(Class<?> type);  
      14.     // }  
      15.     try {  
      16.       Class<?> unsafeClass = Class.forName("sun.misc.Unsafe");  
      17.       Field f = unsafeClass.getDeclaredField("theUnsafe");  
      18.       f.setAccessible(true);  
      19.       final Object unsafe = f.get(null);  
      20.       final Method allocateInstance = unsafeClass.getMethod("allocateInstance", Class.class);  
      21.       return new UnsafeAllocator() {  
      22.         @Override  
      23.         @SuppressWarnings("unchecked")  
      24.         public <T> T newInstance(Class<T> c) throws Exception {  
      25.           return (T) allocateInstance.invoke(unsafe, c);  
      26.         }  
      27.       };  
      28.     } catch (Exception ignored) {  
      29.     }  
      30.   
      31.     ...  
      32.       
      33.     // give up  
      34.     return new UnsafeAllocator() {  
      35.       @Override  
      36.       public <T> T newInstance(Class<T> c) {  
      37.         throw new UnsupportedOperationException("Cannot allocate " + c);  
      38.       }  
      39.     };  
      40.   }  
      41. }  

      去掉反射后,代碼看起來大概是這樣:

      1. public abstract class UnsafeAllocator {    
      2.   public abstract <T> T newInstance(Class<T> c) throws Exception;    
      3.     
      4.   public static UnsafeAllocator create() {  
      5.       return new UnsafeAllocator() {    
      6.         @Override    
      7.         @SuppressWarnings("unchecked")    
      8.         public <T> T newInstance(Class<T> c) throws Exception {    
      9.           Unsafe unsafe = sun.misc.Unsafe.theUnsafe; // <--  
      10.           return (T) unsafe.allocateInstance(c); // <--  
      11.         }    
      12.       };   
      13.   }  
      14. }  

      那么final字段是怎么處理的?

      答案是,通過反射。詳細情況可以參考這個問題,下面我們僅通過代碼來證明這一點:

      1. class MyObj {  
      2.       
      3.     public final int x;  
      4.       
      5.     public MyObj(int x) { // <---  
      6.         this.x = x;  
      7.     }  
      8.       
      9. }  
      1. @Test  
      2. public void setFinal() throws Exception {  
      3.     MyObj obj = new MyObj(1);  
      4.     Assert.assertEquals(1, obj.x);  
      5.       
      6.     Field f = obj.getClass().getField("x");  
      7.     f.setAccessible(true); // <---  
      8.     f.set(obj, 2);  
      9.     Assert.assertEquals(2, obj.x);  
      10. }  
      測試通過!

      結論

      反序列化時,如果一個類沒有默認構造函數(shù),那么GSON是通過JDK內部API來創(chuàng)建對象實例的,并且通過反射final字段賦值。

      這種做法通常是很危險的,所以非專業(yè)人士請勿效仿


        本站是提供個人知識管理的網絡存儲空間,所有內容均由用戶發(fā)布,不代表本站觀點。請注意甄別內容中的聯(lián)系方式、誘導購買等信息,謹防詐騙。如發(fā)現(xiàn)有害或侵權內容,請點擊一鍵舉報。
        轉藏 分享 獻花(0

        0條評論

        發(fā)表

        請遵守用戶 評論公約

        類似文章 更多