最近在按照第三行代码书上的内容写sunnyWeather项目,前几天明明刚看的泛型初始化,今天再看一遍,又一脸懵逼了,还是记录一下吧,在记录的过程中加强记忆。
在Android项目中,通常使用Retrofit框架来请求网络,在没有使用Kotlin特性之前,通常是这样写的。
object BaseHttpHelper {
private val retrofit: Retrofit by lazy {
Retrofit.Builder()
.addConverterFactory(GsonConverterFactory.create())
.baseUrl(Const.BASE_URL)
.build()
}
public fun <T> getApiService(serviceClass: Class<T>): T {
return retrofit.create(serviceClass)
}
}
然后在使用的地方这样写即可
BaseHttpHelper.getApiService(PlaceService::class.java)
然后我们来使用泛型实例化。
在Java中泛型由于有类型擦除的存在,所以不允许我们对泛型的类型进行判断或是进行一些操作,所以如果我们想要对getApiService()方法再精简一些,这样写,代码就会报错
fun <T> getApiService(): T {
return retrofit.create(T::class.java)
}
错误信息为:Cannot use T as reified type parameter.use a class instead。
也就是T不能作为具体化类型的参数,而要使用一个class类。
那我们应该怎么改呢? 使用reified关键字,使用了这个关键字以后我们就可以在函数参数中写T::class.java了。
注意,reified关键字只允许在kotlin内联函数中使用,为什么呢?我们先看优化以后的代码再讲为什么。
object ServiceCreator {
private val retrofit = Retrofit.Builder()
.baseUrl(Const.BASE_URL)
.addConverterFactory(GsonConverterFactory.create())
.build()
fun <T> create(serviceClass: Class<T>): T = retrofit.create(serviceClass)
inline fun <reified T> create(): T = create(T::class.java)
}
我们在调用的位置直接写
val placeService = ServiceCreator.create<PlaceService>()
即可。为什么呢?因为内联啊,实际上内联函数就是在调用的位置把整个函数给搬过去了,上面的代码实际上就等于
val placeService = ServiceCreator.create(PlaceService::class.java)
所以说可以这样写,实际上kotlin并没有对java做出突破,它只是在java的基础上添加了很多语法小技巧,可以方便我们开发者写更少一点的代码,达到相同的效果。