原因是我们Person没有提供默认的构造方法,Gson在没有找到默认构造方法时,它就直接通过Unsafe的方法,绕过了构造方法,直接构建了一个对象。
到这里,我们收获了:
Gson是如何构建对象的?
我们在写需要Gson转化为对象的类的时候,一定要记得有默认的构造方法,否则虽然不报错,但是很不安全!
我们了解到了还有这种Unsafe黑科技的方式构造对象。
4.1、使用 data class 没有设置无参构造函数
在 Kotlin 中,不需要自己动手去写一个 JavaBean,可以直接使用 DataClass,使用 DataClass 编译器会默默地帮我们生成一些函数。例如:
data class Person(var name: String, var age: Int) {}
这个Bean是用于接收服务器数据,通过Gson转化为对象的。例如:
val gson = Gson() val person = gson.fromJson<Person>("{"age":"12"}", Person::class.java) println(person.name)
我们传递了一个json字符串,但是没有包含key为name的值,并且注意:
在Person中name的类型是String,也就是说是不允许name=null的
输出结果:
null
是不是有些奇怪,感觉意外绕过了Kotlin的空类型检查。那么是什么原因导致的呢?
原因是:Person在被转Java代码时,只会生成一个包含两个参数的构造方法,没有提供默认的构造方法。Gson在通过反射创建对象时,会优先尝试获取无参构造函数。如果没有找到无参构造函数时,它就直接通过Unsafe的方法,绕过了构造方法,直接构建了一个对象。
因此我们在使用 data class,在遇到上面类似需求的时候,最好提供一个无参构造方法。
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")