本篇笔记主要记录过去几年 工作所需Kotlin的进阶技术,查漏补缺
- 更多参考:https://www.yiibai.com/kotlin
0,Kotlin泛型和注解
- 架构开发的利器
- 开发出来的框架更加通用
- 能够帮助你研究和理解别的框架
- 自己造轮子需要,能用泛型和注解解决问题
泛型
fun main(){
println(Milk().taste().price)
BlueColor(Blue()).printColor()
test()
}
interface Drinks<T>{
fun taste():T
fun price(t:T)
}
class Price{
val price = 5
}
class Milk:Drinks<Price>{
override fun taste():Price{
println("Price")
return Price()
}
override fun price(t:Price){
println("Milk price:${t.price}")
}
}
/**
* 泛型类
*/
abstract class Color<T>(var t:T){
abstract fun printColor()
}
class Blue{
val color = "Blue"
}
class BlueColor(t:Blue):Color<Blue>(t){
override fun printColor(){
println("color: ${t.color}")
}
}
/* 泛型方法 */
fun <T> fromJson(json:String,tClass:Class<T>):T?{
val t:T? = tClass.newInstance()
return t
}
/* 泛型约束 */
fun <T:Comparable<T>?> sort(list:List<T>?):Unit{}
fun test(){
sort(listOf(5,2,3,4))
val listString = listOf("a","b","c")
val list = listTest(listString,"a")//大于a的才输出
println(list)
}
//泛型多个上界的情况,用where限制
fun <T> listTest(list:List<T>,threshold:T):List<T>
where T:CharSequence,
T:Comparable<T> {
return list.filter{it > threshold}.map{it}
}
/* Price
* 5
* color: Blue
* [b, c]
*/
在Kotlin中Out代表协变,in代表逆变,以下为对比:
//kotlin使用处协变
fun sumOfList(list:List<out Number>)
//Java上界通配符
void sumOfList(List<? extends Number> list)
//kotlin使用处逆变
fun addNumbers(list:List<in Int>)
//java 下界通配符
void addNumbers(List<? super Interger> list)
注解
@Target(AnnotationTarget.CLASS)
annotation class ApiDoc(val value:String)
@ApiDoc("modify class")
class Box{
// @ApiDoc("修饰字段")
val size = 6
// @ApiDoc("修饰方法")
fun test(){
}
}
实例: 通过注解判断api是get还是post
fun main(){
fire(ApiGetArt())
}
public enum class Method{
GET,POST
}
@Target(AnnotationTarget.CLASS)
annotation class HttpMethod(val method:Method)
interface Api{
val name:String
val version:String
get() = "1.0"
}
@HttpMethod(Method.GET)
class ApiGetArt:Api{
override val name:String
get() = "/api.getArt"
}
fun fire(api:Api){
val annotation = api.javaClass.annotations
val method = annotation.find{it is HttpMethod } as? HttpMethod
println("通过注解得到该接口需要通过: ${method?.method} 方法请求")
}
// 返回的结果:
// 通过注解得到该接口需要通过: GET 方法请求
1,Kotlin中的扩展Extensions
Why?为啥要用扩展?
- 提供架构的易用性
- 减少代码量,让代码更加整洁,纯粹
- 提高编码的效率,生产力提高
泛型扩展方法
//更换一个数组的坐标元素值
fun main(){
printSwap()
}
fun printSwap(){
val list = mutableListOf(2,6,7)
list.swapInt(0,1)
println("list.swapInt(0,1):${list}")
val listString = mutableListOf("ab","c")
listString.swapT(0,1)
println("listT.swapT(0,1):${listString}")
}
//单扩展Int
fun MutableList<Int>.swapInt(index1:Int,index2:Int){
val temp = this[index1]
this[index1] = this[index2]
this[index2] = temp
}
//对单扩展做泛型,支持多种类型参数
fun <T> MutableList<T>.swapT(index1:Int,index2:Int){
val temp = this[index1]
this[index1] = this[index2]
this[index2] = temp
}
/** 结果
* list.swap(0,1):[6, 2, 7]
* listT.swap(0,1):[c, ab]
*/
扩展属性
fun main(){
println("字符串「12ABC的最后一个字」:${"12ABC的最后一个字".lastChar}")
}
//为String添加一个lastChar属性,用于获取字符串的最后一个字符
val String.lastChar:Char get() = this.get(this.length-1)
//结果:字符串「12ABC的最后一个字」: 字
为伴生对象添加扩展
/**为伴生对象添加扩展 */
fun main(){
Jump.print("伴生对象扩展")
}
class Jump{
companion object{}
}
fun Jump.Companion.print(str:String){
println(str)
}
//结果: 伴生对象扩展
2,Kotlin中的常用扩展方法
let
主要作用:避免null操作,限制作用域
fun main(){
testLet(null)
testLet("Let")
}
fun testLet(str:String?){
//避免为null的操作,let里面永远不为null
str?.let{
println(it.length)
}
//限制作用域
str.let{
val str2 = "let 作用域"
println(it+str2)
}
}
// 返回结果:
// nulllet 作用域
// 3
// Letlet 作用域
Run
省事,在run代码块里面可以直接调用函数的属性
fun main(){
testRun(People("HL",30))
}
data class People(val name:String,val age:Int)
fun testRun(p:People){
p.run{
println("Name:$name,Age:$age")
}
}
//结果:Name:HL,Age:30
Apply
调用某个对象的apply函数,在函数范围类可以任意调用该对象的任意方法,并返回该对象
fun main(){
testApply()
}
fun testApply(){
ArrayList<String>().apply{
add("a")
add("b")
}.let{
println(it)
}
}
//结果:[a,b]
实战代码实例(此例类似Android中Kotlin的layout扩展)
使用kotlin扩展为控件绑定监听器减少模板代码
fun <T:View> Activity.find(@IdRes id:Int):T{
return findViewById(id)
}
fun Int.onClick(activity:Activity,click:()->Unit){
activity.find<View>(this).apply{
setOnClickListener{
click()
}
}
}
//上面代码应用在Activity中:
val tv = find<TextView>(R.id.tv)
R.id.tv.onClick(this){
//处理点击事件
}