Kotlin入门笔记

版权声明:仅供参考,请勿深度复制。愿世界对我们温柔以待 https://blog.csdn.net/u010913414/article/details/82283921

1.基础语法(引用部分代码来自菜鸟教程)

主函数:和java不一样的是没有被类包裹,看到了熟悉的println函数。

kotlin中有一个少见的就是变量写法:变量名 :类型(第一个字母大写)

不用写分号

fun main(args: Array<String>) {    // 包级可见的函数,接受一个字符串数组作为参数
   println("Hello World!")         // 分号可以省略
}

关键字列表

  • fun  :函数声明
  • vararg:
  • field:后端变量
  • super

函数:

函数定义:fun是关键字,fun sum(a:Int,b:Int):Int{}   最后的:Int表示函数最终返回整形数据

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

表达式也可以作为函数定义:这个时候,返回类型自动判断,public声明的要明确类型

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

public fun sum(a: Int, b: Int): Int = a + b   // public 方法则必须明确写出返回类型
无返回值函数:Unit,可以省略,Unit与c++的void一样
fun printSum(a: Int, b: Int): Unit { 
    print(a + b)
}

可变参数长度的函数:vararg:声明v是动态的整形数据,感觉像php与js的弱类型样子。

fun vars(vararg v:Int){
    for(item in v){
        print(item)
    }
}

// 测试
fun main(args: Array<String>) {
    vars(1,2,3,4,5)  // 输出12345
}

匿名函数:

fun main(args: Array<String>) {
    val sumLambda: (Int, Int) -> Int = {x,y -> x+y}
    println(sumLambda(1,2))  // 输出 3
}

常量与变量

这kotlin分为可变和固定的类似于JS的const变量:关键字 val是不可变常量 var 是变量;Kotlin这真是集百家之大长啊,JS,C++,C,PHP,(JAVA不会,很尴尬啊,听说kt和它很接近)都有影子。。。

val <标识符> : <类型> = <初始化值>
var <标识符> : <类型> = <初始化值>

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


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

字符串模板:PHP里双引号中得$name可以识别为变量

$ 表示一个变量名或者变量值

$varName 表示变量值

${varName.fun()} 表示变量的方法返回值:

var a = 1
// 初始化a=1
val s1 = "a is $a" 
//初始化常量s1,嵌套了一个$a等同于 val s1="a is 1"

a = 2
// 重新复制a
val s2 = "${s1.replace("is", "was")}, but now is $a"
//输出: a was 1 ,but now is 2
//replace("原字符串","新字符串")
// ${} 返回里面变量执行方法后的值

区间

fun main(args: Array<String>) {
    print("循环输出:")
    for (i in 1..4) print(i) // 输出“1234”
    println("\n----------------")
    print("设置步长:")
    for (i in 1..4 step 2) print(i) // 输出“13”,第二次输出位数移动两位
    println("\n----------------")
    print("使用 downTo:")
    for (i in 4 downTo 1 step 2) print(i) // 输出“42”,倒序输出 ,指定step为2
    println("\n----------------")
    print("使用 until:")
    // 使用 until 函数排除结束元素
    for (i in 1 until 4) {   // i in [1, 4) 直到4停止输出,开区间
        print(i)
    }
    println("\n----------------")
}

NULL空指针处理

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


fun main(args: Array<String>) {
  if (args.size < 2) {
    print("Two integers expected")
    return
  }
  val x = parseInt(args[0])
  val y = parseInt(args[1])
  // 直接使用 `x * y` 会导致错误, 因为它们可能为 null.
  if (x != null && y != null) {
    // 在进行过 null 值检查之后, x 和 y 的类型会被自动转换为非 null 变量
    print(x * y)
  }
}

类型判断与转换:js用typeof判断类型,用(string)等强制转换类型

fun getStringLength(obj: Any): Int? {
  if (obj is String) {
    // 做过类型判断以后,obj会被系统自动转换为String类型
    return obj.length 
  }

  //在这里还有一种方法,与Java中instanceof不同,使用!is
  // if (obj !is String){
  //   // XXX
  // }

  // 这里的obj仍然是Any类型的引用
  return null
}

fun getStringLength(obj: Any): Int? {
  if (obj !is String)
    return null
  // 在这个分支中, `obj` 的类型会被自动转换为 `String`
  return obj.length
}
fun getStringLength(obj: Any): Int? {
  // 在 `&&` 运算符的右侧, `obj` 的类型会被自动转换为 `String`
  if (obj is String && obj.length > 0)
    return obj.length
  return null
}

 

基本数据类型

Byte、Short、Int、Long、Float、Double(字符串独立的数据类型)

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
//这个操作没见过,_下划线是会被自动去除吗?

比较两个数字

Kotlin 中没有基础数据类型,只有封装的数字类型,你每定义的一个变量,其实 Kotlin 帮你封装了一个对象,这样可以保证不会出现空指针。数字类型也一样,所有在比较两个数字的时候,就有比较数据大小和比较两个对象是否相同的区别了。

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

这里说说JS,JS里面数据类型都有两种方法初始化,一种就是对象的实例化,另一种就是原始值的方法。

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

    //创建新的对象把引用a的字面量给boxedA,但是内存地址是不一样的
    val boxedA: Int? = a//初始化boxedAInt:?可以为空,否则需要判断是否为空
    val anotherBoxedA: Int? = a
//同上,新对象,字面量一样,但是内存地址不一致

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

类型转换:name.toInt()/String/

val b: Byte = 1 // OK, 字面值是静态检测的
val i: Int = b // 错误
我们可以代用其toInt()方法。

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

数据类型

  • 字符 char
    fun decimalDigitValue(c: Char): Int {
        if (c !in '0'..'9')
            throw IllegalArgumentException("Out of range")
        return c.toInt() - '0'.toInt() // 显式转换为数字
    }
  • 数组
    fun main(args: Array<String>) {
        //[1,2,3]
        val a = arrayOf(1, 2, 3)
        //[0,2,4],array函数
        val b = Array(3, { i -> (i * 2) })
    //参数一是指定长度,参数二是对象,i指针默认指向0
        //对象实例化
        //读取数组内容
        println(a[0])    // 输出结果:1
        println(b[1])    // 输出结果:2
    }
  • 字符串
    for (c in str) {
        println(c)
    }
    //循环遍历每一个字符
    
    fun main(args: Array<String>) {
        val text = """
        多行字符串
        多行字符串
        """
        println(text)   // 输出有一些前置空格,多行字符
    }
    
    fun main(args: Array<String>) {
        val text = """
        |多行字符串
        |菜鸟教程
        |多行字符串
        |Runoob
        """.trimMargin()
        println(text)    // 前置空格删除了
    }
    默认 | 用作边界前缀,但你可以选择其他字符并作为参数传入,比如 trimMargin(">")。

条件语句

// 作为表达式
val max = if (a > b) a else b
//使用区间
fun main(args: Array<String>) {
    val x = 5
    val y = 9
    if (x in 1..8) {
        println("x 在区间内")
    }
}

//switch基本一样 
//when 也可以用来取代 if-else if链。 如果不提供参数,所有的分支条件都是简单的布尔表达式,而当一个分支的条件为真时则执行该分支:
when (x) {
    1 -> print("x == 1")
    2 -> print("x == 2")
    else -> { // 注意这个块
        print("x 不是 1 ,也不是 2")
    }
}

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")
}

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

fun main(args: Array<String>) {
    val items = setOf("apple", "banana", "kiwi")
    when {
        "orange" in items -> println("juicy")
        "apple" in items -> println("apple is fine too")
    }
}

循环控制

for (item in collection) print(item)

//如果你想要通过索引遍历一个数组或者一个 list,你可以这么做:

for (i in array.indices) {
    print(array[i])
}

for ((index, value) in array.withIndex()) {
    println("the element at $index is $value")
}

 

返回和跳转

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

  • return。默认从最直接包围它的函数或者匿名函数返回。
  • break。终止最直接包围它的循环。
  • continue。继续下一次最直接包围它的循环。

Break 和 Continue 标签

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

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

标签处返回

fun foo() {
    ints.forEach {
        if (it == 0) return
        print(it)
    }
}
//foo 中返回

fun foo() {
    ints.forEach lit@ {
        if (it == 0) return@lit
        print(it)
    }
}
//lambda返回
fun foo() {
    ints.forEach {
        if (it == 0) return@forEach
        print(it)
    }
}
//同上

//或者,我们用一个匿名函数替代 lambda 表达式。 匿名函数内部的 return 语句将从该匿名函数自身返回

fun foo() {
    ints.forEach(fun(value: Int) {
        if (value == 0) return
        print(value)
    })
}
//当要返一个回值的时候,解析器优先选用标签限制的 return,即

return@a 1

类与对象

类定义:

val site = Runoob() // Kotlin 中没有 new 关键字

类属性定义

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

实例:kotlin中,初始化变量时,“=”,系统会自动调用setter()函数,field关键字

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 关键词只能用于属性的访问器,如以上实例:

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

主构造器

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

class Person constructor(firstName: String) {
    init {
        println("FirstName is $firstName")
    }
}

创建一个 Runoob类,并通过构造函数传入网站名:

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("菜鸟教程")
    println(runoob.siteName)
    println(runoob.url)
    println(runoob.country)
    runoob.printTest()
}

嵌套类和内部类在使用时的区别

(1)创建对象的区别

var demo = Outter.Nested()// 嵌套类,Outter后边没有括号
var demo = Outter().Inner();// 内部类,Outter后边有括号

引用外部类的成员变量的方式不同

先来看嵌套类:

class Outer {                  // 外部类
    private val bar: Int = 1
    class Nested {             // 嵌套类
        var ot: Outer = Outer()
        println(ot.bar) // 嵌套类可以引用外部类私有变量,但要先创建外部类的实例,不能直接引用
        fun foo() = 2
    }
}

再来看一下内部类(引用文章中代码):

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

可以看来内部类可以直接通过 this@ 外部类名 的形式引用外部类的成员变量,不需要创建外部类对象;

继承

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

class Example // 从 Any 隐式继承
//重写
//在基类中,使用fun声明函数时,此函数默认为final修饰,不能被子类重写。如果允许子类重写该函数,那么就要手动添加 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();

}

Kotlin 数据类与密封类

。。未完待续,持续学习!

猜你喜欢

转载自blog.csdn.net/u010913414/article/details/82283921