简介
Kotlin由JetBrains公司开发。谷歌宣布其成为安卓第一开发语言。
兼容Java,可以和Java混编。
语言类型
- 编译型
编译器直接将源代码一次性编译成与CPU相配的二进制文件,计算机可直接执行,例如C,C++。
特点:一次编译。不同操作系统(编译的后二进制文件需要调用此OS的api)和CPU(指令集)需要重新编译。
tip:编译后的文件,如果想要在另一个机器上跑,需要相同的操作系统(需要调用此系统的API),还需要相同的CPU(指令集)
- 解释型
程序运行时,解释器会将源码一行一行实时解析成二进制再执行。例如JS,Python。
特点:安装对应的VM即可运行。效率低。
Java的语言类型:
java准确来说属于混合型语言,但更偏向于解释型。
编译:java存在JIT和AOT,JIT将可将热点代码直接编译成机器码,AOT可在安装时把代码编译成机器码
解释:java运行时需编译成class文件,JVM在解释class文件。
基本
变量、函数
fun main(args: Array<String>){
val a = 1 // 定义变量。推导为Int(包装类)。
var b = 2 // 定义常量
println(myFun(4, 5))
}
fun test() {} // 无参无返
// 下面等效
fun myFun(a: Int, b: Int): Int { // 有参有返
return a + b
}
fun myFun(a: Int, b: Int): Int = a + b
fun myFun(a: Int, b: Int) = a + b // 推导类型
val:定义只读变量,可以是任何类型
const:常量,值必须在编译时已知,并且只能是基本数据类型或 String
条件
fun getMax(a: Int, b: Int) = if (a > b) a else b // 此处必须有else,否则无返报错
// Kotlin中==等价于Java的equals比较的时是对象里的内容
fun myIf(name: String): String{
if (name == "D") return "不及格"
else return "Others" // 此处必须有else,否则无返报错
}
fun getScore(name: String) = when (name) {
"A" -> "best"
"B" -> "better"
else -> "bad" // 此处必须有else,否则无返报错
}
// when 参数检查
fun checkNumber(num: Number) {
when(num){
is Int -> println("Integer")
is Double -> println("Double")
else -> println("others") // 可以省略,因为无返
}
}
循环
// 输出 0 ≤ .. ≤ 10
val range = 0..10 // [0, 10]
val range = 0 until 10 // [0, 10)
val range = 0 until 10 step 2 // 同上,步长为2
val range = 10 downTo 0 // [10, 0]
for (i in range) {
println(i)
}
类
// Demo1: 拥有主构造器
// 如果不带open,decompile则为final,不可继承
open class Person(val name: String, val age: Int) {
init {
println("name = " + name + ", age = " + age)
}
}
// 主构造。如果父类有主构造则子类必须调用。无参的主构造也是
class Student(name: String, age: Int, val number: String, val grade: Int) : Person(name, age) {
// 次构造调用主构造
constructor(name: String, age: Int, number: String) : this(name,age,number,0)
constructor() : this("", 0, "", 0)
}
fun main(args: Array<String>){
// 每次创建类都会调用Person类中的init代码块
val s1 = Student("Tom", 18, "123456", 6) // 打印信息。
val s2 = Student("Tommy", 19, "123457")
val s3 = Student()
}
// Demo2: 没有主构造器
open class Person(name: String, age: Int) {
init {
println("name = " + name + ", age = " + age)
}
}
class Student : Person{
// num不可以在其他地方使用,报错。
constructor(name: String, age: Int, num: String) : super(name, age) // 调用父类的构造器
}
fun main(args: Array<String>){
val s1 = Student("Tom", 18, "123456")
}
接口
interface Study {
fun read()
// 和java(default,static除外)不同,可以在接口中直接实现
fun eat() {
println("eat...")
}
}
// 类继承父类和接口
class Student : Person, Study{
override fun read() {
println("read...")
}
}
数据类data
Idea中创建Data类
// 在java中
public class UserBean {
private String id;
private String name;
private String pwd;
// 拥有get/set方法,空构造器和所有属性的构造器
// 重写equals、hashCode、toString方法
}
// 在kotlin中
// 拥有有get/set方法
class UserBean(var id: String, var name: String, var pwd: String)
// data会自动重写equals、hashCode、toString方法
data class UserBean(var id: String, var name: String, var pwd: String)
fun main(args: Array<String>){
val user = UserBean("123", "Tom", "123456")
user.name = "Bob" // 本质在调用set方法
println(user.name) // 本质在调用get方法
}
单例object
Idea中创建object类
object Singleton {
fun test() {
println("test")
}
}
// 使用
fun main(args: Array<String>){
Singleton.test() // 相等于java代码为Singleton.INSTANCE.test();
}
decomplie的java文件
public final class Singleton {
@NotNull
public static final Singleton INSTANCE;
public final void test() {
String var1 = "test";
System.out.println(var1);
}
private Singleton() {
}
static {
Singleton var0 = new Singleton();
INSTANCE = var0;
}
}
集合
// Demo1: List
val list = ArrayList<Int>();
list.add(1);
list.add(2);
val listOf = listOf<Int>(1, 2, 3) // 不可变
println(listOf.get(1))
val mutableListOf = mutableListOf<Int>(1, 2, 3) // 可变
mutableListOf.add(4)
println(mutableListOf.get(2))
for (i in mutableListOf) {
println(i)
}
// Demo2: Set 相似与List
// Demo3: Map
val map = HashMap<String, String>()
map.put("1", "Tom")
map.put("2", "Alice")
map["3"] = "Bob" // 等效上面。hashmap指向类似下标的操作
map["4"] = "Jerry"
// 等效println(map.get("3"))
println(map["3"])
val mapOf = mapOf<String, String>("1" to "Tom", "2" to "Bob") // 不可变
val mutableMapOf = mutableMapOf<String, String>("1" to "Tom", "2" to "Bob") // 可变
mutableMapOf.put("3", "alice")
// Hashmap遍历
for (mutableEntry in mutableMapOf) {
println(mutableEntry.toString())
}
for ((key, value) in mutableMapOf) {
println(key + " " + value)
}
Lambda
List
val listOf = listOf<String>("a", "bb", "ccc", "dddd")
var maxLengthString = "" // 常规方法
for (s in listOf) {
if (s.length > maxLengthString.length) maxLengthString = s;
}
println(maxLengthString)
// 等效
var lambda = {str: String -> str.length}
println(listOf.maxByOrNull(lambda)) // maxByOrNull是一个普通方法,需要一个Lambda参数
// 等效
listOf.maxByOrNull(){str: String -> str.length} // 若Lambda为方法的最后一个参数,则可将{}提到外面
listOf.maxByOrNull {str: String -> str.length} // 若有且仅有一个参数且是Lambda,则可去掉()
listOf.maxByOrNull {str -> str.length} // kotlin有推导机制
listOf.maxByOrNull {it.length} // 若Lambda只有一个参数,则可用it(iterator)替代参数名
// 类型的方法
listOf.filter { it.length > 2 } // 过滤长度大于2的字符串
listOf.map { it.toUpperCase() } // 字符全部转为大写
listOf.any {it.length > 3} // 是否有长度大于3的字符串
listOf.all { it.length > 1 } // 是否有长度均大于1的字符串
Thread
// object用于实现接口,即声明匿名内部类
Thread(object : Runnable {
override fun run() {
println("test")
}
}).start()
// Runnable是Java单抽象方法接口,可对代码进行简化
Thread( Runnable {
println("test")
}).start()
// Runnable接口只用一个方法,使用Lambda
Thread({
println("test")
}).start()
// Thread只需一个参数Runnable参数,则可省略()
Thread { println("test") }.start()
只要是只接受一个函数式接口的,都可以这样写。比如button.setOnClickListener { println("test") }
空指针检查机制
在java中处理空指针
public void doStudy(Study study) {
study.doHomework();
study.readBooks();
}
// 上述代码时存在空指针风险的,传入null,则程序崩溃
public void doStudy(Study study) {
if (study != null) {
study.doHomework();
study.readBooks();
}
}
对于kotlin来说
// kotlin会在编译期自动检查
fun study(study: Study) {
study.doHomework()
study.readBooks()
}
fun main() {
study(null) //报错
study(Student()) //正确
}
// `?`表示可以传入null
fun study(study: Study?) {
if (study != null) { // 程序员必须要保证不会空
study.doHomework()
study.readBooks()
}
}
// `?.`表示非空才执行
fun study(study: Study?) {
study?.doHomework() // study不空才执行方法
study?.readBooks()
}
//此时靠?.则保证了study肯定不为空,才会执行let函数
fun study(study: Study?) {
study?.let {
//it为study
it.doHomework()
it.readBooks()
}
}
// `?:` 表示a不空才为b
val c = a ?: b
// Demo: 例子
fun getTextLength(text: String?) = text?.length ?: 0
fun getTextLength(text: String?): Int {
if (text != null) {
return text.length
}
return 0
}
// 强行通过编译,就需要依靠`!!`,这时就是程序员来保证安全
fun study(study: Study?) {
//假设此时为空抛出异常,则和java一样
study!!.doHomework()
study!!.readBooks()
}
// study可以为Study也可为空
var study: Study? = null
内嵌表达式
fun main(args: Array<String>){
val name = "World"
println("Hello $name") // $name等效于${name}
println("Win ${if (2 > 1) 2 else "1"}") // ${if...}
println("fun ${say("World")}") // // ${fun()}
}
fun say(content: String): String = "say $content"
函数参数默认值
// Demo1:
fun main(args: Array<String>){
say(100)
say(100, "World")
}
fun say(num: Int, str: String = "default") {
println("num = $num, str = $str")
}
// Demo2: 指定形参传实参
fun main(){
say(2, "Tom")
say(str = "Bob") // 不传具有默认值的
}
fun say(num: Int = 100, str: String) { // 默认值在前面
println("num = $num, str = $str")
}
构造器中的默认值
class Student(name: String, age: Int, val number: String, val grade: Int) : Person(name, age){
constructor(name: String, age: Int, number: String) : this(name, age, number, 0) {
}
...
}
// 等效于上面
class Student(name: String, age: Int, val number: String, val grade: Int = 0) : Person(name, age){
...
}
TODO
TODO()
是一个有效的表达式,且返回类型是 Nothing
,表示该代码永远不会正常返回。
public fun TODO(reason: String? = null): Nothing = throw NotImplementedError(reason)
为什么不会报错?
override fun onBind(intent: Intent): IBinder {
TODO("Return the communication channel to the service.")
}
因为 Nothing
是所有类型的子类型,可以暂时替所有类的返回值。编译正确,运行抛出相应异常。
block
作为高阶参数
// 高阶函数参数,允许将代码块(函数或 lambda 表达式)作为参数供函数使用,实现更灵活的代码逻辑和复用。
inline fun <T> myFun(condition : Boolean, block: () -> T): T? {
return if (condition) block() else null
}
fun main() {
val myFun = myFun(true) {
println("hello world")
"abc"
}
println(myFun)
}
T.()
的形式就是定义扩展函数的方式。
// kotlin的Unit( = Java中的void)
// 定义一个扩展函数类型 T.() -> Unit
fun <T> myFun(obj: T, block: T.() -> Unit) {
// 在 T 对象上调用扩展函数
obj.block()
}
// 为 String 类型定义一个扩展函数
fun String.printToupper() {
println(this.uppercase())
}
fun main() {
val str = "hello"
myFun(str){
printToupper() // 调用扩展函数
}
}
//Demo2 : apply 函数本质上就是一个 T.() -> Unit 类型的函数
val mutableList = mutableListOf<Int>(1, 2, 3).apply {
add(4)
add(5)
}
apply源码
@kotlin.internal.InlineOnly
public inline fun <T> T.apply(block: T.() -> Unit): T {
contract {
callsInPlace(block, InvocationKind.EXACTLY_ONCE)
}
// 等效this.block(),this就是调用apply的对象
block()
return this
}
委托模式
fun main(){
val consolePrint = ConsolePrinter()
val document = Document(consolePrint)
document.printer("hello") // ConsolePrint : hello
document.say("hello") // say : hello
}
interface Printer{
fun printer(content : String)
fun say(content : String)
}
class ConsolePrinter : Printer{
override fun printer(content : String) {
println("ConsolePrint : $content")
}
override fun say(content: String) {
println("say : $content")
}
}
// Document类通过by printer委托了Printer接口的所有方法给了printer对象
class Document(printer : Printer) : Printer by printer {}