类
默认为 pulic
class Two { var x:Int = 0;//必须初始化 //构造方法 constructor(x:Int){ this.x = x } //定义方法 fun y(){ } }
简写
class Two(var x: Int) { var y: Int = x } class A(var y: Int) { } class B(var x: Int, var y: String) { } fun main() { val two = Two(1) println(two.y + two.x) val a = A(3) println(a.y) val b = B(3, "hello") println(b.y + " " + b.x) }
接口
interface SimpleInf { val x: Int var y: Int fun simpleMethod() } class Two() : SimpleInf { //实现 接口中的参数,因为是可读,所以必须 + get 方法 override val x: Int = 0 get() { return field } override var y: Int = 10 get() { return field } set(value) { field = value } //必须写 override override fun simpleMethod() { println(x) println(y) } } //在构造方法中直接初始化 接口中的变量 class A(override val x: Int, override var y: Int) : SimpleInf { override fun simpleMethod() { println(x) println(y) } } fun main() { val t = Two() t.simpleMethod() // 0 ,10 //获取属性引用 val g = t::y g.set(5) println(t.simpleMethod()) //0 ,5 val a = A(3, 3) a.simpleMethod() //3 ,3 }
抽象类
abstract class Two { abstract fun abs() //方法默认不可复写需要复写则需要加 open 关键字 open fun over() { } //不可复写 fun non() { } } class A : Two() { override fun abs() { TODO("not implemented") //To change body of created functions use File | Settings | File Templates. } override fun over() { super.over() } //non 方法不能重写 }
类继承
open class Two { open fun a() {} open fun b() {} fun c() {} } //继承的类必须加 Open open class A : Two() { //重写的方法必须是 open override fun a() { super.a() } //将重写类方法变为不可重写 final override fun b() { super.b() } } class B : A() { override fun a() { super.a() } }
属性
Kt 中不需要我们定义 get / 和 set 方法,就算是定义了,使用的时候也是通过 类.属性的方式来读写,而不是 get / set,如下
class Persion { var name: String = "" get() { return field //field 表示 属性:name } set(value) { field = value //设置 value } // get 和 set 推荐不用写 var age: Int = 0 } fun main() { val p = Persion() println(p.name) println(p.age) }
扩展方法/属性
fun main() { val s = String::setEmail val s1: (String, String) -> String = String::setEmail val fiel = PoorGuy::moneyLeft var fiel1: KMutableProperty1<PoorGuy, Double> = PoorGuy::pocket } class PoorGuy { var pocket: Double = 0.0 } //扩展方法 fun PoorGuy.noMoney() { } //扩展属性 var PoorGuy.moneyLeft: Double get() { return pocket; } set(value) { pocket = value } //扩展 String 类方法 fun String.setEmail(s: String): String { return "${s}@163.com" }
某个类的扩展方法如果定义在别的类中:
class D2 { fun Class<D1>.set() { } }
如何调用呢,如下:
class D2 { fun Class<D1>.set() { } //在内部调用 fun X() { D1().javaClass.set() } } fun main() { //其实 run 也是一个扩展方法 D2().run { D1().javaClass.set() } }
空类型安全的概念
var nonNull:String = "hello" // nonNull = null //不可空类型
任何 类型在类型后面+?即为可 null
var nonNull: String? = "hello" val length = nonNull!!.length //强转为 Null val l = nonNull?.length //nonNull 如果为 null,则 l 也为 null,否则返回对应的长度
那 如果 l 也 为 null 呢?可以采用如下方式:
val x: Int = nonNull?.length ?: 0 //elvis 表达式,表达式为 null 返回 0
空类型继承关系
fun main() { var x: String = "Hello" var y: String? = "World" x = y //类型不匹配 y = x //Ok ,根据李氏替换原则就可知道 String 应该是 String?的子类 //里氏替换原则说:任何基类可以出现的的地方,子类一定可以出现 // 也就是子类在一切场景下都可以替换他的父类 //例如 Int 是 Number 的子类 var a: Int = 2; var b: Number = 2; a = b; //类型不匹配 b = a; //从上面就可以看出 String 应该是 String?子类 }
平台类型
Kt 代码可以编译为字节码类型,还有 JavaScript ,Natvie。。
智能类型转换
fun main() { val k: KotLiner = Person() // is 等价于 instanceof,判断一个类型是否为一个类型 if (k is Person) { //智能转换为 Person println(k.name) } }
类型的安全转换
println((k as? Person)?.name)
转换 成功,就会得到 Person 类型,否则就是 null
例子
使用 Retrofit 发送一个网络请求
首先,加一下依赖
implementation 'com.squareup.retrofit2:retrofit:2.6.2' implementation 'com.squareup.retrofit2:converter-gson:2.6.2' implementation 'com.google.code.gson:gson:2.8.1'
接着发送请求:
interface Api { // Retrofit @GET("/repos/{owner}/{repo}") fun getRepository(@Path("owner") owner: String, @Path("repo") repo: String): Call<Repository> } fun main() { val api = Retrofit.Builder().baseUrl("https://api.github.com") .addConverterFactory(GsonConverterFactory.create()) .build() .create(Api::class.java) val response = api.getRepository("Jetbrains", "kotlin").execute() val repository = response.body() if (repository == null) { println("Error!{${response.code()} - ${response.message()}") } else { println(repository.name) println(repository.owner.login) println(repository.stargazers_count) println(repository.forks_count) //生成一个文件 File("Kotlin.html").writeText( """ <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>${repository.owner.login} - ${repository.owner.login} - ${repository.name}</title> </head> <body> <h1> <a href = '${repository.html_url}'>${repository.owner.login}-${repository.name}</a></h1> <p>${repository.description}</p> <p>Start:${repository.stargazers_count}</p> <p>Forks:${repository.forks_count}</p> </body> </html> """.trimIndent() ) } }
//结果 kotlin JetBrains 30195 3602
总结
类和接口
类:实例化不用写 new ,方法,类被继承或者重写必须加上 open 关键字,构造器可以写在类后面
接口
抽象类:基本和上面的差不多,override 作为关键字使用,而不是注解
属性:field+getter+setter,不需要手动的 get / set。属性引用
扩展方法
定义方法
方法/函数引用,在方法签名+类,函数引用,直接 :: 函数
空类型安全
可空类型为不可空类型的父类。Kt 中声明类型的时候就可以明确的告诉编译器类型是否可以为 null,如果不可为 null,编译器就会有权利要求你不能给他赋值为 null
运算符
!! :强制转换为不可空 类型
?. :安全调用成员,如果不确定是否为空,可以使用这种方式,如果为 null,整个表达式返回 null,
?: :上述如果表达式返回 null 可以使用 ?: 返回一个默认值
平台类型
Java 虚拟机上就是 java 原生类型
javaScript 上就是 javaScript 的类型
Native 则是 C 对应的类型
智能类型替换
A as B 类型转换
A as? B 安全类型转换,失败返回 null
只能类型转换的适用场景
Retrofit 发送网络请求
使用 Java 的第三方框架
使用 KotLin 的文件扩展写文件
使用 Raw 字符串
建议
尽可能使用 val 声明不可变引用,让程序的含义更加清晰确定
尽可能减少对外部变量的访问,也为函数式编程提供基础
必要时创建局部的变量指向外部,避免因它的变化引起程序错误
这种方式,如果为 null,整个表达式返回 null,
- ?: :上述如果表达式返回 null 可以使用 ?: 返回一个默认值
平台类型
Java 虚拟机上就是 java 原生类型
javaScript 上就是 javaScript 的类型
Native 则是 C 对应的类型
智能类型替换
A as B 类型转换
A as? B 安全类型转换,失败返回 null
只能类型转换的适用场景
Retrofit 发送网络请求
使用 Java 的第三方框架
使用 KotLin 的文件扩展写文件
使用 Raw 字符串