91超碰碰碰碰久久久久久综合_超碰av人澡人澡人澡人澡人掠_国产黄大片在线观看画质优化_txt小说免费全本

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

kotlin gson反序列化默認值失效深入講解

發布時間:2020-08-30 21:49:55 來源:腳本之家 閱讀:387 作者:尋找極限的貓 欄目:移動開發

Gson反序列化原理

原理簡述

gson反序列化主要分為兩個過程:

  • 根據TypeToken創建出對象
  • 根據json字符串解析數據,對對象屬性賦值

對象的創建

ConstructorConstructor.get

  • 先嘗試獲取無參構造函數
  • 失敗則嘗試List、Map等情況的構造函數
  • 最后使用Unsafe.newInstance兜底(此兜底不會調用構造函數,導致所有對象初始化代碼不會調用)
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>() {
  @Override 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>() {
  @Override public T construct() {
   return rawTypeCreator.createInstance(type);
  }
  };
 }
 // 獲取無參構造函數
 ObjectConstructor<T> defaultConstructor = newDefaultConstructor(rawType);
 if (defaultConstructor != null) {
  return defaultConstructor;
 }

 // 獲取List<T>,Map<T>等構造函數,對于List,Map的情況
 ObjectConstructor<T> defaultImplementation = newDefaultImplementationConstructor(type, rawType);
 if (defaultImplementation != null) {
  return defaultImplementation;
 }

 // unSafe構造出對象,不調用任何的構造函數
 // finally try unsafe
 return newUnsafeAllocator(type, rawType);
 }

ConstructorConstructor.newDefaultConstructor

  • 調用Class.getDeclaredConstructor獲取無參構造函數
private <T> ObjectConstructor<T> newDefaultConstructor(Class<? super T> rawType) {
 try {
  // 獲取無參構造函數
  final Constructor<? super T> constructor = rawType.getDeclaredConstructor();
  if (!constructor.isAccessible()) {
  accessor.makeAccessible(constructor);
  }

ConstructorConstructor.newUnsafeAllocator

  • 調用UnSafe.newInstance創建出對象
  • 不會調用構造函數,因此所有的初始化的代碼都不會被調用
private <T> ObjectConstructor<T> newUnsafeAllocator(
  final Type type, final Class<? super T> rawType) {
 return new ObjectConstructor<T>() {
  private final UnsafeAllocator unsafeAllocator = UnsafeAllocator.create();
  @SuppressWarnings("unchecked")
  @Override public T construct() {
  try {
  // 
   Object newInstance = unsafeAllocator.newInstance(rawType);
   return (T) newInstance;
  } catch (Exception e) {
   throw new RuntimeException(("Unable to invoke no-args constructor for " + type + ". "
    + "Registering an InstanceCreator with Gson for this type may fix this problem."), e);
  }
  }
 };
 }

結論

  • Gson反序列要工作正常,使結果符合預期的話,要求類必須有一個無參構造函數

kotlin構造函數默認參數和無參構造函數的關系

參數里面存在沒有默認值的情況

kotlin代碼

  • id沒有默認值
class User(val id: Int, val name: String = "sss") {
 init {
  println("init")
 }
}

反編譯的Java代碼

  • 包含兩個構造函數,一個是我們聲明的全參數構造函數,另一個是kotlin生成的輔助構造函數
  • 不包含無參構造函數
public final class User {
 private final int id;
 @NotNull
 private final String name;
 
 public User(int id, @NotNull String name) {
  Intrinsics.checkParameterIsNotNull(name, "name");
  super();
  this.id = id;
  this.name = name;
  String var3 = "init";
  System.out.println(var3);
 }

 // $FF: synthetic method
 public User(int var1, String var2, int var3, DefaultConstructorMarker var4) {
  if ((var3 & 2) != 0) {
   var2 = "";
  }

  this(var1, var2);
 }
}

gson反序列化輸出

代碼:

 @Test
 fun testJson() {
  val user = Gson().fromJson("{}", User::class.java)
  print(user.name)
 }

輸出:不符合預期(我們聲明的非空的name實際結果是null)

null
Process finished with exit code 0

參數都包含默認參數的情況

kotlin代碼

class User(val id: Int=1, val name: String = "sss") {
 init {
  println("init")
 }
}

反編譯Java代碼

  • 除了上面的兩個構造函數,多了一個無參構造函數(從邏輯上講,這個也符合預期)
public final class User {
 private final int id;
 @NotNull
 private final String name;

 public User(int id, @NotNull String name) {
  Intrinsics.checkParameterIsNotNull(name, "name");
  super();
  this.id = id;
  this.name = name;
  String var3 = "init";
  System.out.println(var3);
 }

 // $FF: synthetic method
 public User(int var1, String var2, int var3, DefaultConstructorMarker var4) {
  if ((var3 & 1) != 0) {
   var1 = 1;
  }

  if ((var3 & 2) != 0) {
   var2 = "";
  }

  this(var1, var2);
 }

 // 無參構造函數
 public User() {
  this(0, (String)null, 3, (DefaultConstructorMarker)null);
 }
}

gson反序列化輸出

代碼:

 @Test
 fun testJson() {
  val user = Gson().fromJson("{}", User::class.java)
  print(user.name)
 }

輸出:符合預期

init
sss
Process finished with exit code 0

Best Practice

Practice1

  • 屬性聲明在構造函數,所有參數都帶默認值
  • 不確定的參數聲明為可空
class User(val id: Int=1 , val name: String = "sss") {
 init {
  println("init")
 }
}

Practice2

回歸到Java的寫法即可

class User {
 val id: Int = 1
 val name: String = "sss"

 init {
  println("init")
 }
}

總結

以上就是這篇文章的全部內容了,希望本文的內容對大家的學習或者工作具有一定的參考學習價值,如果有疑問大家可以留言交流,謝謝大家對億速云的支持。

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

广东省| 义乌市| 城固县| 安康市| 凭祥市| 台江县| 红河县| 博乐市| 新民市| 达拉特旗| 保德县| 民乐县| 濮阳市| 高淳县| 房山区| 鄄城县| 永德县| 出国| 铁岭县| 灌阳县| 略阳县| 南安市| 墨脱县| 三都| 唐海县| 宁河县| 涡阳县| 如皋市| 新民市| 营口市| 河东区| 疏附县| 四川省| 丁青县| 民权县| 奉贤区| 台南县| 南江县| 嘉善县| 名山县| 沽源县|