Kotlin笔记

为什么是Kotlin?

下面是官网给的解释


开发IDE : IDEA / Android Studio
参考:Kotlin 语言中文站
总之Kotlin是目前最有可能取代Java的一门语言,你说你要不要学?

Kotlin基础语法

函数定义

函数定义使用关键字fun,参数格式为:参数:类型

fun sum(a: Int, b: Int): Int {   // Int 参数,返回值 Int
    return a + b
}

表达式作为函数体时,返回类型自动判断

fun sum(a: Int, b: Int) = a + b

注意

// public 方法则必须明确写出返回类型
public fun sum(a: Int, b: Int): Int = a + b   

无返回值的函数(类似Java中的void):

fun printSum(a: Int, b: Int): Unit { 
    print(a + b)
}


// 如果是返回 Unit类型,则可以省略(对于public方法也是这样):
public fun printSum(a: Int, b: Int) { 
    print(a + b)
}

常量定义和变量定义

  1. 可变变量定义:var关键字
var <标识符> : <类型> = <初始化值>
  1. 不可变变量定义:val 关键字,只能赋值一次的变量(类似Java中final修饰的变量)
val <标识符> : <类型> = <初始化值>

常量与变量都可以没有初始化值,但是在引用前必须初始化
编译器支持自动类型判断,即声明时可以不指定类型,由编译器判断。

示例:

val a: Int = 1
val b = 1       // 系统自动推断变量类型为Int
val c: Int      // 如果不在声明时初始化则必须提供变量类型
c = 1           // 明确赋值


var x = 5        // 系统自动推断变量类型为Int
x += 1           // 变量可修改

注释

和java类似,支持单行注释和多行注释,不同的是,Kotlin中的块注释允许嵌套

// 这是一个单行注释

/* 这是一个多行的
   块注释。 */

字符串模板

$ 表示一个变量名或者变量值
$varName 表示变量值
${varName.fun()} 表示变量的方法返回值

var a = 1
// 模板中的简单名称:
val s1 = "a is $a" 

a = 2
// 模板中的任意表达式:
val s2 = "${s1.replace("is", "was")}, but now is $a"

NULL 检查机制

Kotlin的空安全设计对于声明可为空的参数,在使用时要进行空判断处理,有两种处理方式,字段后加!!像Java一样抛出空异常,另一种字段后加?可不做处理返回值为 null或配合?:做空判断处理

//类型后面加?表示可为空
var age: String? = "23" 
//抛出空指针异常
val ages = age!!.toInt()
//不做处理返回 null
val ages1 = age?.toInt()
//age为空返回-1
val ages2 = age?.toInt() ?: -1

区间

区间表达式由具有操作符形式 .. 的 rangeTo 函数辅以 in 和 !in 形成。
区间是为任何可比较类型定义的,但对于整型原生类型,它有一个优化的实现。以下是使用区间的一些示例:

    for (i in 1..4) print("$i ")    //输出1 2 3 4
    println()
    for (i in 4..1) print("$i ")    //什么也不输出4
    println()
    for (i in 4 downTo 1) print("$i ")    //倒序应该用downTo
    println()

    for (i in 1..10) {
        // 等同于 1 <= i && i <= 10
        //[1,10]
        print("$i ")
    }
    println()

    // 使用 until 函数排除结束元素
    for (i in 1 until 10) {
        // 等同于 1 <= i && i < 10
        //[1,10)
        print("$i ")
    }
    println()

    for (i in 1..4 step 2) print("$i ")         //输出1 3
    println()

    for (i in 4 downTo 1 step 2) print("$i ")   //输出4 2
    println()

Kotlin基本数据类型

类型 位宽度
Double 64
Float 32
Long 64
Int 32
Short 16
Byte 8

比较两个数字

在 Kotlin 中,三个等号 === 表示比较对象地址,两个 == 表示比较两个值大小。

fun main(args: Array<String>) {
    val a: Int = 10000
    println(a === a) // true,值相等,对象地址相等

    //经过了装箱,创建了两个不同的对象
    val boxedA: Int? = a
    val anotherBoxedA: Int? = a

    //虽然经过了装箱,但是值是相等的,都是10000
    println(boxedA === anotherBoxedA) //  false,值相等,对象地址不一样
    println(boxedA == anotherBoxedA) // true,值相等
}

类型转换

每种数据类型都有下面的这些方法,可以转化为其它的类型:

toByte(): Byte
toShort(): Short
toInt(): Int
toLong(): Long
toFloat(): Float
toDouble(): Double
toChar(): Char

例如:

val b: Byte = 1 // OK, 字面值是静态检测的
val i: Int = b.toInt() // OK

Kotlin条件控制

Kotlin中表达条件控制的有两种表达式

  1. if表达式
  2. when表达式

if表达式的用法

其实个人感觉对于if的用法,java和kotlin并没有什么区别,有点不太一样的就是可以把if表达式的结果赋值给一个变量,如下:

val max = if (a > b) {
    print("Choose a")
    a
} else {
    print("Choose b")
    b
}

所以也就可以有下面这样的写法了

val c = if (condition) a else b

when表达式的用法

when表达式就和java里面的switch类似,最简单的形式如下:

when (x) {
    1 -> print("x == 1")
    2 -> print("x == 2")
    else -> { // 注意这个块
        print("x 不是 1 ,也不是 2")
    }
}

在when语句中,else同switch语句中的default,如果其他分支都不满足条件将会进入else分支,当然,如果很多分支需要相同的处理方式,可以把多个分支条件放在一起,用逗号分隔,例如:

when (x) {
    0, 1 -> print("x == 0 or x == 1")
    else -> print("otherwise")
}

我们也可以检测一个值在(in)或者不在(!in)一个区间或者集合中:

when (x) {
    in 1..10 -> print("x is in the range")
    in validNumbers -> print("x is valid")
    !in 10..20 -> print("x is outside the range")
    else -> print("none of the above")
}

另一种可能性是检测一个值是(is)或者不是(!is)一个特定类型的值。注意: 由于智能转换,你可以访问该类型的方法和属性而无需 任何额外的检测。

fun hasPrefix(x: Any) = when(x) {
    is String -> x.startsWith("prefix")
    else -> false
}

实例:

fun main(args: Array<String>) {
    val x = 0
    if (x > 0) {
        println("x大于0")
    } else if (x == 0) {
        println("x等于0")
    } else {
        println("小于0")
    }

    val a = 1
    val b = 2
    val c = if (a >= b) a else b
    println("c的值为 $c")

    when (x) {
        0, 1 -> println("x==0 or x==1")
        else -> println("otherwise")

    }

    when (x) {
        1 -> println("x==1")
        2 -> println("x==2")
        else -> {
            println("x 不是1,也不是2")
        }
    }

    when (x) {
        in 0..10 -> println("x在该区间范围内")
        else -> println("x不在该区间范围内")
    }
}

Kotlin循环控制

和Java一样,kotlin循环也有三种形式,for循环,while循环和do....while循环。但是用法却有些不同。

for循环

基本用法如下:

for (item: Int in ints) {
    // ……
}

实例如下:

fun main(args: Array<String>) {
    val items = listOf("apple", "banana", "kiwi")
    for (item in items) {
        println(item)
    }

    for (index in items.indices) {
        println("item at $index is ${items[index]}")
    }
}

执行结果如下:

apple
banana
kiwi
item at 0 is apple
item at 1 is banana
item at 2 is kiwi

注意!!

在kotlin中使用的for循环语句和java里面的for循环语句相类似,但是不可以使用
for(int i=0;i<n;i++)这样的语句

while循环和do...while循环

while循环是最基本的循环方式,基本结构为:

while( 布尔表达式 ) {
 //循环内容
}

do...while 循环的基本结构为:

do {
       //代码语句
}while(布尔表达式);

理解起来和Java里面的while循环和do...while循环一致,参考实例如下:

fun main(args: Array<String>) {
    println("----while 使用-----")
    var x = 5
    while (x > 0) {
        println( x--)
    }
    println("----do...while 使用-----")
    var y = 5
    do {
        println(y--)
    } while(y>0)
}

输出结果:

----while 使用-----
5
4
3
2
1
----do...while 使用-----
5
4
3
2
1

循环返回和跳转

Kotlin 有三种结构化跳转的表达式:

  1. return
  2. break
  3. continue
    理解起来和Java中的一样,基本用法也一致,但是在kotlin中break和continue有新的用法

Break 和 Continue 标签

在 Kotlin 中任何表达式都可以用标签(label)来标记。 标签的格式为标识符后跟 @ 符号,例如:abc@、fooBar@都是有效的标签。 要为一个表达式加标签,我们只要在其前加标签即可。

loop@ for (i in 1..100) {
    for (j in 1..100) {
        if (……) break@loop
    }
}

标签限制的 break 跳转到刚好位于该标签指定的循环后面的执行点。 continue 继续标签指定的循环的下一次迭代。

通过指定标签就可以明确的指定出在什么时候退出哪一个循环

Kotlin类和对象

Kotlin类中可以包含以下几个东西:

  1. 构造函数和初始化代码块
  2. 成员函数
  3. 属性
  4. 内部类
  5. 对象声明

Kotlin中使用关键字class声明类,后面紧跟类名,在类中可以定义成员函数,格式如下:

class Temp{
    //类名为Temp
    //大括号里面是类体构成
    fun f(){
        println("这是成员函数")
    }
}

类的属性

类的属性用关键字var声明为可变的,否则就用val声明为不可变

class Temp{
    var name: String = ……
    var url: String = ……
    var city: String = ……
}

也可以像使用普通函数那样使用构造函数创建类实例:

val temp= Temp() // Kotlin 中没有 new 关键字

想要使用一个属性,只需要用名称引用即可

temp.name
temp.url

这里需要注意的是,kotlin中并没有new关键字,实例化一个对象的时候不需要像java一样通过new关键字实例化。

getter和setter

getter和setter属性都是可选的,用法和c#中的get和set方法类似
如果属性类型可以从初始化语句或者类的成员函数中推断出来,那就可以省去类型

注意!!! val不允许设置setter函数,因为该函数是只读的。

var allByDefault: Int? // 错误: 需要一个初始化语句, 默认实现了 getter 和 setter 方法
var initialized = 1    // 类型为 Int, 默认实现了 getter 和 setter
val simple: Int?       // 类型为 Int ,默认实现 getter ,但必须在构造函数中初始化
val inferredType = 1   // 类型为 Int 类型,默认实现 getter

实例

下面实例定义了一个Person类,包含两个可变变量 lastName 和 no,lastName 修改了 getter 方法,no 修改了 setter 方法。

class Person {

    var lastName: String = "zhang"
        get() = field.toUpperCase()   // 将变量赋值后转换为大写
        set

    var no: Int = 100
        get() = field                // 后端变量
        set(value) {
            if (value < 10) {       // 如果传入的值小于 10 返回该值
                field = value
            } else {
                field = -1         // 如果传入的值大于等于 10 返回 -1
            }
        }

    var heiht: Float = 145.4f
        private set
}

// 测试
fun main(args: Array<String>) {
    var person: Person = Person()

    person.lastName = "wang"

    println("lastName:${person.lastName}")

    person.no = 9
    println("no:${person.no}")

    person.no = 20
    println("no:${person.no}")

}

输出结果为:

lastName:WANG
no:9
no:-1

Kotlin 中类不能有字段。提供了 Backing Fields(后端变量) 机制,备用字段使用field关键字声明,field 关键词只能用于属性的访问器

主构造器和次构造器

Koltin 中的类可以有一个 主构造器,以及一个或多个次构造器,主构造器是类头部的一部分,位于类名称之后:

class Person constructor(firstName: String) {}

如果主构造器没有任何注解,也没有任何可见度修饰符,那么可以省略constructor关键字

class Person(firstName: String) {}

主构造器

主构造器中不能包含任何代码,初始化代码可以当在初始化代码段中,用init关键字作为前缀

class Person constructor(firstName: String) {
    init {
        System.out.print("FirstName is $firstName")
    }
}

实例:

class Runoob  constructor(name: String) {  // 类名为 Runoob
    // 大括号内是类体构成
    var url: String = "http://www.runoob.com"
    var country: String = "CN"
    var siteName = name

    init {
        println("初始化网站名: ${name}")
    }

    fun printTest() {
        println("我是类的函数")
    }
}

fun main(args: Array<String>) {
    val runoob =  Runoob("菜鸟教程")
    println(runoob.siteName)
    println(runoob.url)
    println(runoob.country)
    runoob.printTest()
}

次构造函数

类也可以有二级构造函数,并且可以有多个,需要加前缀constructor

class Person { 
    constructor(parent: Person) {
        parent.children.add(this) 
    }
}

如果类有主构造函数,每个次构造函数都要,或直接或间接通过另一个次构造函数代理主构造函数。在同一个类中代理另一个构造函数使用 this 关键字:

class Person(val name: String) {
    constructor (name: String, age:Int) : this(name) {
        // 初始化...
    }
}

实例:

class Runoob  constructor(name: String) {  // 类名为 Runoob
    // 大括号内是类体构成
    var url: String = "http://www.runoob.com"
    var country: String = "CN"
    var siteName = name

    init {
        println("初始化网站名: ${name}")
    }
    // 次构造函数
    constructor (name: String, alexa: Int) : this(name) {
        println("Alexa 排名 $alexa")
    }

    fun printTest() {
        println("我是类的函数")
    }
}

fun main(args: Array<String>) {
    val runoob =  Runoob("菜鸟教程", 10000)
    println(runoob.siteName)
    println(runoob.url)
    println(runoob.country)
    runoob.printTest()
}

Kotlin继承

kotlin中所有的类都继承Any类,如果一个类要被继承,需要使用open关键字进行修饰

open class Base(p: Int)           // 定义基类

class Derived(p: Int) : Base(p)

构造函数

子类有主构造函数,则基类必须在主构造函数中立即初始化

open class Person(var name : String, var age : Int){// 基类

}

class Student(name : String, age : Int, var no : String, var score : Int) : Person(name, age) {

}

// 测试
fun main(args: Array<String>) {
    val s =  Student("Runoob", 18, "S12346", 89)
    println("学生名: ${s.name}")
    println("年龄: ${s.age}")
    println("学生号: ${s.no}")
    println("成绩: ${s.score}")
}

子类中没有主构造函数

如果子类没有主构造函数,则必须在每一个二级构造函数中用 super 关键字初始化基类,或者在代理另一个构造函数。初始化基类时,可以调用基类的不同构造方法。

/**用户基类**/
open class Person(name:String){
    /**次级构造函数**/
    constructor(name:String,age:Int):this(name){
        //初始化
        println("-------基类次级构造函数---------")
    }
}

/**子类继承 Person 类**/
class Student:Person{

    /**次级构造函数**/
    constructor(name:String,age:Int,no:String,score:Int):super(name,age){
        println("-------继承类次级构造函数---------")
        println("学生名: ${name}")
        println("年龄: ${age}")
        println("学生号: ${no}")
        println("成绩: ${score}")
    }
}

fun main(args: Array<String>) {
    var s =  Student("Runoob", 18, "S12345", 89)
}

重写

如果允许子类重写,那么就要手动添加open修饰,重写的方法用override关键词修饰:

/**用户基类**/
open class Person{
    open fun study(){       // 允许子类重写
        println("我毕业了")
    }
}

/**子类继承 Person 类**/
class Student : Person() {

    override fun study(){    // 重写方法
        println("我在读大学")
    }
}

fun main(args: Array<String>) {
    val s =  Student()
    s.study();

}

如果有多个相同的方法(继承或者实现自其他类,如A、B类),则必须要重写该方法,使用super范型去选择性地调用父类的实现。

open class A {
    open fun f () { print("A") }
    fun a() { print("a") }
}

interface B {
    fun f() { print("B") } //接口的成员变量默认是 open 的
    fun b() { print("b") }
}

class C() : A() , B{
    override fun f() {
        super<A>.f()//调用 A.f()
        super<B>.f()//调用 B.f()
    }
}

fun main(args: Array<String>) {
    val c =  C()
    c.f();

}

Kotlin接口

在kotlin中接口和java8中的用法类似,都是用interface关键字定义接口,允许有默认方法的实现。

接口中的方法

实例:

interface MyInterface {
    fun bar()
    fun foo() {
        // 可选的方法体
        println("foo")
    }
}
class Child : MyInterface {
    override fun bar() {
        // 方法体
        println("bar")
    }
}
fun main(args: Array<String>) {
    val c =  Child()
    c.foo();
    c.bar();
}

接口中的属性

接口中的属性只能是抽象的,不允许初始化值,接口不会爆粗 属性值,实现接口的时候,必须重写属性。
实例:

interface MyInterface {
    var name:String //name 属性, 抽象的
    fun bar()
    fun foo() {
        // 可选的方法体
        println("foo")
    }
}
class Child : MyInterface {
    override var name: String = "runoob" //重载属性
    override fun bar() {
        // 方法体
        println("bar")
    }
}
fun main(args: Array<String>) {
    val c =  Child()
    c.foo();
    c.bar();
    println(c.name)
 
}

函数重写

接口中的方法的重写和继承类中的方法重写类似,实例如下:

interface A {
    fun foo() { print("A") }   // 已实现
    fun bar()                  // 未实现,没有方法体,是抽象的
}
 
interface B {
    fun foo() { print("B") }   // 已实现
    fun bar() { print("bar") } // 已实现
}
 
class C : A {
    override fun bar() { print("bar") }   // 重写
}
 
class D : A, B {
    override fun foo() {
        super<A>.foo()
        super<B>.foo()
    }
 
    override fun bar() {
        super<B>.bar()
    }
}
 
fun main(args: Array<String>) {
    val d =  D()
    d.foo();
    d.bar();
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,711评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,079评论 3 387
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 159,194评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,089评论 1 286
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,197评论 6 385
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,306评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,338评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,119评论 0 269
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,541评论 1 306
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,846评论 2 328
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,014评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,694评论 4 337
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,322评论 3 318
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,026评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,257评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,863评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,895评论 2 351

推荐阅读更多精彩内容

  • 前言 人生苦多,快来 Kotlin ,快速学习Kotlin! 什么是Kotlin? Kotlin 是种静态类型编程...
    任半生嚣狂阅读 26,179评论 9 118
  • 第一次知道kotlin这个语言是在JakeWharton的这个dex-method-list 项目里,本来这个项目...
    dodomix阅读 13,374评论 4 15
  • a === b 当且仅当 a 和 b 指向同一个对象时求值为 true。 如果为语句加上双感叹号:!! 那么则表示...
    麦兜叮叮当阅读 423评论 0 1
  • 不好
    天上云_fa03阅读 186评论 0 0
  • 嘿. 你今天. 过得还好嘛. 这里是温火. 第一次正式发简书. 我和我的名字一样. 不冷不热. 不主动. 不热情....
    Hoo温火阅读 139评论 0 0