美文网首页
Kotlin入门

Kotlin入门

作者: 小米Metre | 来源:发表于2018-09-12 17:45 被阅读0次

一、什么是kotlin?

Kotlin,现代多平台静态编程语言。由JetBranis开发,于2012年2月发布v1.0版本。2017年成为android的官方支持的开发语言。

多平台,可以编译成java字节码,在jvm上运行,也可以编程js在浏览器上运行。

image.png

静态,可以静态检测常见异常,比如NullPointerException。

二、为什么要使用kotlin?

1、简洁

大大减少了代码行的数量。

2、安全

避免了空指针异常。

3、互操作性

充分利用 JVM、Android 和浏览器的现有库。

JVM JavaScript
4、工具友好

可用任何 Java IDE 或者使用命令行构建。

三、基础语法

a、不需要分号结束。
b、实例化类不需要new。

1、函数定义
    fun sum(a:Int,b:Int):Int{
        return a+b
    }
等于:
    fun sum(a:Int,b:Int) = a+b
等于:
    fun sum(a:Int,b:Int):Int= a+b
等于:
    val sum:(Int,Int)->Int = {x,b -> x+b}
    println(sum(3,5))//输出 8

无返回值:
    fun sum(a:Int,b:Int):Unit{
        println("$a,$b")
    }
等于:
    fun sum(a:Int,b:Int){
        println("$a,$b")
    }

2、可变长参数函数
fun main(args: Array<String>) {
     Test().vans(1,2,4,5)
}

class Test {
    fun vans(vararg v: Int) {
        v.iterator().forEach {
            print("$it,") //输出:1,2,4,5,
        }
    } 
}
3、lambda表达式
    val filters =  list
            .filter { it.age >=10 }

    filters.forEach({
          println(it.toString())
      })
4、定义常量与变量

定义常量用 val 定义。类似Java Final。
可变变量用 var 定义。

  var f = listOf("a","b")
    f = listOf("a","b") 编译通过

  val f = listOf("a","b")
    f = listOf("a","b") 编译失败   Error:(24, 5) Kotlin: Val cannot be reassigned
5、字符串模板
$表示一个变量名或者变量值
$varName 表示变量值
${varName.fun()} 表示变量的方法返回值:

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

val sum: (Int, Int) -> Int = { x, b -> x + b }
println("sum == ${sum(3, 5)}")//输出 : sum == 8
6、NULL检查机制

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

//类型后面加?表示age可为空,否则编译不通过。
var age: String? = "23" 

// “!!” 表示age如果为null,则抛出空指针异常 KotlinNullPointerException
val ages = age!!.toInt()

// “?” 表示如果age为空,则不做处理,直接返回 null,ages1也是为null。
val ages1 = age?.toInt()  // age为null,则ages1也是null。 


//age为空,则返回-1
val ages2 = age?.toInt() ?: -1
7、类型检测及自动类型转换

使用 is 运算符检测一个表达式是否某类型的一个实例(类似于Java中的instanceof关键字)。

fun getStringLength(obj: Any): Int? { //Any为任意类型,(类似Java中的Object)
  if (obj is String) {
    // 做过类型判断以后,obj会被系统自动转换为String类型,无需再强转
    return obj.length 
  }
}
8、区间

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

    for(i in 1..4) print(i) // 输出“1234”
    for(i in 4..1) print(i)// 什么都不输出
    for(i in 4 downTo 1) print(i) //输出 “4321”
    for (i in 1..4 step 2) print(i) //  使用 step 指定步长 输出“13”

    // 使用 until 函数排除结束元素
    for (i in 1 until 10) {   // i in [1, 10) 排除了 10
        println(i) //输出 123456789
    }

四、Kotlin 基本数据类型

Kotlin 的基本数值类型包括 Byte、Short、Int、Long、Float、Double 等。不同于Java的是,字符不属于数值类型,是一个独立的数据类型。

类型 位宽度
Double 64
Float 32
Long 64
Int 32
Short 16
Byte 8
1、字面常量

字面常量
下面是所有类型的字面常量:

十进制:123
长整型以大写的 L 结尾:123L
16 进制以 0x 开头:0x0F
2 进制以 0b 开头:0b00001011
注意:8进制不支持
Kotlin 同时也支持传统符号表示的浮点数值:

Doubles 默认写法: 123.5, 123.5e10
Floats 使用 f 或者 F 后缀:123.5f
可以使用下划线使数字常量更易读:

    val oneMillion = 1_000_000
    val creditCardNumber = 1234_5678_9012_3456L
    val socialSecurityNumber = 999_99_9999L
    val hexBytes = 0xFF_EC_DE_5E
    val bytes = 0b11010010_01101001_10010100_10010010
2、比较两个数字

Kotlin中,没有基础数据类型,只有封装好的数字类型,每定义一个变量,Kotlin都会创建一个对象,它保证了不会出现空指针。所以在比较两个数的时候,就出现了两次方式。“==” 和 “===”。两个等号比较内容,三个等号比较地址。

    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,值相等
3、类型转换

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

toByte(): Byte
toShort(): Short
toInt(): Int
toLong(): Long
toFloat(): Float
toDouble(): Double
toChar(): Char
4、位操作符

对于Int和Long类型,还有一系列的位操作符可以使用,分别是:

shl(bits) – 左移位 (Java’s <<)
shr(bits) – 右移位 (Java’s >>)
ushr(bits) – 无符号右移位 (Java’s >>>)
and(bits) – 与
or(bits) – 或
xor(bits) – 异或
inv() – 反向
5、字符
//和 Java 不一样,Kotlin 中的 Char 不能直接和数字操作,Char 必需是单引号 ' 包含起来的。比如普通字符 '0','a'。
fun decimalDigitValue(c: Char): Int {
    if (c !in '0'..'9')
        throw IllegalArgumentException("Out of range")
    return c.toInt() - '0'.toInt() // 显式转换为数字
}
6、数组
    //[1,2,3]
    val a = arrayOf(1, 2, 3)
    //[0,2,4]
    val b = Array(3, { i -> (i * 2) }) 
7、集合 List、Set、Map

与大多数语言不同,Kotlin 区分可变集合与不可变集合(lists、sets、maps 等)。精确控制什么时候集合可编辑有助于消除 bug 以及设计良好的 API。

不可变集合:

Kotlin 的 List<out T> 类型是一个提供只读操作如 size、get等的接口。与 Java 类似,它继承自 Collection<T> 进而继承自 Iterable<T>。

val readWriteMap= listOf(1, 2, 3)
val readWriteMap2 = hashMapOf("foo" to 1, "bar" to 2)
可变集合:

改变 list 的方法是由 MutableList<T> 加入的。这一模式同样适用于 Set<out T>/MutableSet<T> 及 Map<K, out V>/MutableMap<K, V>。

val numbers: MutableList<Int> = mutableListOf(1, 2, 3)
println(numbers)        // 输出 "[1, 2, 3]"

val readOnlyView: List<Int> = numbers
numbers.add(4)
println(readOnlyView)   // 输出 "[1, 2, 3, 4]"
readOnlyView.clear()    //   不能编译

五、Kotlin 条件控制

1、IF 表达式
// 传统用法
var max = a 
if (a < b) max = b

// 使用 else 
var max: Int
if (a > b) {
   max = a
} else {
   max = b
}

// 作为表达式
val max = if (a > b) a else b
2、When 表达式
        when (x){
            1 -> {
                println("---")
                println('1')
            }
            2,3 -> println("2,3")
            else -> println("else")
        }

六、Kotlin 循环控制

//for 循环
for (item in collection) print(item)

//while 与 do...while 循环
while( 布尔表达式 ) {
  //循环内容
}
do {
       //代码语句
}while(布尔表达式);

七、Kotlin 类和对象

class Runoob {  // 类名为 Runoob
    // 大括号内是类体构成
}
//声明一个空类
class Empty

class Person(val name: String) {//主构造函数
    constructor (name: String, age:Int) : this(name) {// 二级构造函数。constructor 
      //: this(name) 表示调用构造函数 Person(val name: String)
        // 初始化...
    }
}
1、抽象类

抽象是面向对象编程的特征之一,类本身,或类中的部分成员,都可以声明为abstract的。抽象成员在类中不存在具体的实现。
注意:无需对抽象类或抽象成员标注open注解。

open class Base {
    open fun f() {}
}
abstract class Derived : Base() {
    override abstract fun f()
}
2、嵌套类
class Outer {                  // 外部类
    private val bar: Int = 1
    class Nested {             // 嵌套类
        fun foo() = 2
    }
}

fun main(args: Array<String>) {
    val demo = Outer.Nested().foo() // 调用格式:外部类.嵌套类.嵌套类方法/属性
    println(demo)    // == 2
}
3、内部类

内部类使用 inner 关键字来表示。
内部类会带有一个对外部类的对象的引用,所以内部类可以访问外部类成员属性和成员函数。

class Outer {
    private val bar: Int = 1
    var v = "成员属性"
    /**嵌套内部类**/
    inner class Inner {
        fun foo() = bar  // 访问外部类成员
        fun innerTest() {
            var o = this@Outer //获取外部类的成员变量
            println("内部类可以引用外部类的成员,例如:" + o.v)
        }
    }
}

fun main(args: Array<String>) {
    val demo = Outer().Inner().foo()
    println(demo) //   1
    val demo2 = Outer().Inner().innerTest()   
    println(demo2)   // 内部类可以引用外部类的成员,例如:成员属性
}
4、匿名内部类
class Test {
    var v = "成员属性"
    fun setInterFace(test: TestInterFace) {
        test.test()
    }
}
// 定义接口
interface TestInterFace {
    fun test()
}
fun main(args: Array<String>) {
    var test = Test()
    //采用对象表达式来创建接口对象,即匿名内部类的实例。
    test.setInterFace(object : TestInterFace {
        override fun test() {
            println("对象表达式创建匿名内部类的实例")
        }
    })
}
5、类的修饰符

类的修饰符包括 classModifier 和accessModifier:

classModifier: 类属性修饰符,标示类本身特性。

abstract    // 抽象类  
final       // 类不可继承,默认属性
enum        // 枚举类
open        // 类可继承,类默认是final的
annotation  // 注解类

accessModifier: 访问权限修饰符。

private    // 仅在同一个文件中可见
protected  // 同一个文件中或子类可见
public     // 所有调用的地方都可见
internal   // 同一个模块中可见

八、Kotlin 继承

Kotlin 中所有类都继承该 Any 类,它是所有类的超类,对于没有超类型声明的类是默认超类:

class Example // 从 Any 隐式继承

//Any 默认提供了三个函数:
equals()
hashCode()
toString()

注意:Any 不是 java.lang.Object。
如果一个类要被继承,可以使用 open 关键字进行修饰。

open class Base(p: Int)           // 定义基类
class Derived(p: Int) : Base(p)
1、重写

在基类中,使用fun声明函数时,此函数默认为final修饰,不能被子类重写。如果允许子类重写该函数,那么就要手动添加 open 修饰它, 子类重写方法使用 override 关键词:

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

    override fun study(){    // 重写方法
        println("我在读大学")
    }
}
fun main(args: Array<String>) {
    val s =  Student()
    s.study();
}
2、属性重写
open class Foo {
    open val x: Int get { …… }
}

class Bar1 : Foo() {
    override val x: Int = ……
}

九、Kotlin 接口

Kotlin 接口与 Java 8 类似,使用 interface 关键字定义接口,允许方法有默认实现

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();
}

十、Kotlin 扩展

1、扩展函数

扩展函数可以在已有类中添加新的方法,不会对原类做修改,扩展函数定义形式:

class User(var name:String)

/**扩展函数,给User类扩展一个Print函数。**/
fun User.Print(){
    print("用户名 $name")
}

fun main(arg:Array<String>){
    var user = User("Runoob")
    user.Print() //输出:用户名 Runoob
}
2、扩展函数是静态解析的(注意:静态解析而非动态解析)

扩展函数是静态解析的,并不是接收者类型的虚拟成员,在调用扩展函数时,具体被调用的的是哪一个函数,由调用函数的的对象表达式来决定的,而不是动态的类型决定的:

open class C

class D: C()

fun C.foo() = "c"   // 扩展函数 foo

fun D.foo() = "d"   // 扩展函数 foo

fun printFoo(c: C) {
    println(c.foo())  // 类型是 C 类
}
fun main(arg:Array<String>){
    printFoo(D())  // 输出:c (如果是动态解析,则应该是输出:d)
}

若扩展函数和成员函数一致,则使用该函数时,会优先使用成员函数。

class C {
    fun foo() { println("成员函数") }
}

fun C.foo() { println("扩展函数") }

fun main(arg:Array<String>){
    var c = C()
    c.foo()  //输出:成员函数
}

十一、Kotlin 数据类与密封类

1、数据类

Kotlin 可以创建一个只包含数据的类,关键字为 data:

data class User(val name: String, val age: Int)

编译器会自动的从主构造函数中根据所有声明的属性提取以下函数:

equals() / hashCode()
toString() 格式如 "User(name=John, age=42)"
componentN() functions 对应于属性,按声明顺序排列
copy() 

如果这些函数在类中已经被明确定义了,或者从超类中继承而来,就不再会生成。
为了保证生成代码的一致性以及有意义,数据类需要满足以下条件:
主构造函数至少包含一个参数。
所有的主构造函数的参数必须标识为val 或者 var ;
数据类不可以声明为 abstract, open, sealed 或者 inner;
数据类不能继承其他类 (但是可以实现接口)。

2、 复制
data class User(val name: String, val age: Int)

fun main(args: Array<String>) {
    val jack = User(name = "Jack", age = 1)
    val olderJack = jack.copy(age = 2)
    println(jack)
    println(olderJack)
}

输出结果为:
User(name=Jack, age=1)
User(name=Jack, age=2)

3、单例
object Site {
   var url:String = ""
   val name: String = "Metre"
}
fun main(args: Array<String>) {
   var s1 =  Site
   var s2 = Site
   s1.url = "www.runoob.com"
   println(s1.url)  //www.runoob.com
   println(s2.url)  //www.runoob.com
}

相关文章

网友评论

      本文标题:Kotlin入门

      本文链接:https://www.haomeiwen.com/subject/tjbsgftx.html