原因是我們Person沒有提供默認(rèn)的構(gòu)造方法,Gson在沒有找到默認(rèn)構(gòu)造方法時(shí),它就直接通過Unsafe的方法,繞過了構(gòu)造方法,直接構(gòu)建了一個(gè)對象。
到這里,我們收獲了:
Gson是如何構(gòu)建對象的?
我們在寫需要Gson轉(zhuǎn)化為對象的類的時(shí)候,一定要記得有默認(rèn)的構(gòu)造方法,否則雖然不報(bào)錯(cuò),但是很不安全!
我們了解到了還有這種Unsafe黑科技的方式構(gòu)造對象。
4.1、使用 data class 沒有設(shè)置無參構(gòu)造函數(shù)
在 Kotlin 中,不需要自己動(dòng)手去寫一個(gè) JavaBean,可以直接使用 DataClass,使用 DataClass 編譯器會默默地幫我們生成一些函數(shù)。例如:
data class Person(var name: String, var age: Int) {}
這個(gè)Bean是用于接收服務(wù)器數(shù)據(jù),通過Gson轉(zhuǎn)化為對象的。例如:
val gson = Gson() val person = gson.fromJson<Person>("{"age":"12"}", Person::class.java) println(person.name)
我們傳遞了一個(gè)json字符串,但是沒有包含key為name的值,并且注意:
在Person中name的類型是String,也就是說是不允許name=null的
輸出結(jié)果:
null
是不是有些奇怪,感覺意外繞過了Kotlin的空類型檢查。那么是什么原因?qū)е碌哪兀?/p>
原因是:Person在被轉(zhuǎn)Java代碼時(shí),只會生成一個(gè)包含兩個(gè)參數(shù)的構(gòu)造方法,沒有提供默認(rèn)的構(gòu)造方法。Gson在通過反射創(chuàng)建對象時(shí),會優(yōu)先嘗試獲取無參構(gòu)造函數(shù)。如果沒有找到無參構(gòu)造函數(shù)時(shí),它就直接通過Unsafe的方法,繞過了構(gòu)造方法,直接構(gòu)建了一個(gè)對象。
因此我們在使用 data class,在遇到上面類似需求的時(shí)候,最好提供一個(gè)無參構(gòu)造方法。
data class GsonDataTest(val name: String, val gender: String) {
constructor(): this(name = "",gender = "")
override fun toString(): String {
return "GsonDataTest(name='$name', gender='$gender')"
}
}
var data:String? = null
var testData = Gson().fromJson<GsonDataTest>(data, GsonDataTest::class.java)
DebugLog.d("aaaaaa", "$testData")
data = ""
testData = Gson().fromJson<GsonDataTest>(data, GsonDataTest::class.java)
DebugLog.d("aaaaaa", "$testData")
data = "{\"name\":\"aa\"}"
testData = Gson().fromJson<GsonDataTest>(data, GsonDataTest::class.java)
DebugLog.d("aaaaaa", "$testData")
data = "{\"name\":\"aa\", \"gender\":\"aa\"}"
testData = Gson().fromJson<GsonDataTest>(data, GsonDataTest::class.java)
DebugLog.d("aaaaaa", "$testData")