Kotlin小菜鸟啊——基础语言教程

332 阅读8分钟

概述

Kotlin是JetBrains推出的一种编程语言,JetBrains是最智能的Java IDE的官方设计器,名为Intellij IDEA。这是在JVM上运行的强静态类型语言。2017年,谷歌宣布Kotlin是Android开发的官方语言。Kotlin是一种开源编程语言,它将面向对象的编程和功能特性组合到一个独特的平台中。内容分为不同的章节,其中包含相关主题以及简单而有用的示例。

Kotlin受其他编程语言(例如Java,Scala,Groovy,Gosu等)的影响。Kotlin的语法可能与JAVA并不完全相似,但是Kotlin在内部依靠现有的Java类库为程序员提供了出色的结果。Kotlin为全球开发人员提供了互操作性,代码安全性和清晰度。

Kotlin特点

  • 简洁 Kotlin比Java更简洁,与Java相比,您需要少写大约40%的代码行。
  • 互操作性 Kotlin与Java具有高度互操作性。在Java项目中使用Kotlin不会遇到任何困难。
  • 开源 Kotlin是一种开源编程语言。

基本语法

2.1、类、方法、变量

1、行末分号可以省略, 2、变量、参数、方法返回的类型写在冒号后面, 3、创建对象不用new, 4、注释和java一样, 5、$p拼接字符串。

package hello                                  //  可选的包头fun main(args: Array<String>) {                // 包级可见的函数,args 参数,Array<String> 参数类型
   println("Hello World!")
   val s = "字符串"
   val str = "$s.length is ${s.length}" // 求值结果为 "runoob.length is 6"
   println(str)
​
    val price = "${'$'}9.99"
    println(price)  // 结果为 $9.99
}
​
fun sum(a: Int, b: Int): Int {                  // Int 参数,返回值 Int
    return a + b
}
​
public fun sum(a: Int, b: Int): Int = a + b     // public 方法则必须明确写出返回类型class Greeter(val name: String) {
   fun greet() { 
      println("Hello, $name")                   // 用$拼接字符串
   }
}
​
fun gg(): Unit {                               // Unit 无返回值,相当于void,也可以省略
    Greeter("World!").greet()                  // 创建一个对象不用 new 关键字
}
​

2.2、var 、val 、vararg

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

vararg 可变产长参数

fun vars(vararg v:Int){
    for(vt in v){
        print(vt)
    }
}
​
fun main(args: Array<String>) {
    vars(1,2,3,4,5)  // 输出12345
}

2.3、匿名函数

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

2.4、NULL检查机制

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

当一个引用可能为 null 值时, 对应的类型声明必须明确地标记为可为 null。 当 str 中的字符串内容不是一个整数时, 返回 null

fun parseInt(str: String): Int? {
    return str.toIntOrNull()
}

2.5、类型判断

fun getStringLength(obj: Any): Int? {
  if (obj is String) {                                          // 单行if,{}可以省略
    // 做过类型判断以后,obj会被系统自动转换为String类型
    return obj.length 
  }
​
  //在这里还有一种方法,与Java中instanceof不同,使用!is
  // if (obj !is String){
  //   // XXX
  // }// 这里的obj仍然是Any类型的引用
  return null
}

2.6、数据类型

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

字面量: 1、长整型以大写的 L 结尾:123L 2、16 进制以 0x 开头:0x0F 3、2 进制以 0b 开头:0b00001011 4、注意:8进制不支持 5、Doubles 默认写法: 123.5, 123.5e10 6、Floats 使用 f 或者 F 后缀:123.5f 7、数字中可以使用下划线,使数字更易读

val hexBytes = 0xFF_EC_DE_5E
val bytes = 0b11010010_01101001_10010100_10010010

在 Kotlin 中,三个等号, 表示比较对象地址,两个等号表示比较两个值大小。 Byte、Short、Int等这些基本类型也有对象地址。

println(a === a) // true,值相等,对象地址相等

toByte()、toShort()、toInt()、toLong()等方法用于类型间转换。

val b: Byte = 1
val i: Int = b.toInt()

Char 不能直接和数字操作,Char 必需是单引号 ’ 包含起来

fun check(c: Char) {
    println(c == 1)                 // false
    println(c == '1')               // true
}

多行字符串可以用三个引号

fun main(args: Array<String>) {
    val text = """
    |第一行
    |第二行
    |第三行
    |第四行
    """.trimMargin()         //  trimMargin() 方法删除多余的空白
    println(text)
}

2.7、异常

fun decimalDigitValue(c: Char): Int {
    if (c !in '0'..'9')
        throw IllegalArgumentException("Out of range")
    return c.toInt() - '0'.toInt()
}

2.8、数组

fun main(args: Array<String>) {
    //[1,2,3]
    val a = arrayOf(1, 2, 3)
    //[0,2,4]
    val b = Array(3, { i -> (i * 2) })
​
    //读取数组内容
    println(a[0])    // 输出结果:1
    println(b[1])    // 输出结果:2
}

2.9、条件控制

var max: Int
if (a > b) {
    max = a
} else {
    max = b
}
​
// 作为表达式
val max = if (a > b) a else b
​
val max = if (a > b) {
    print("Choose a")
    a
} else {
    print("Choose b")
    b
}

when类似 switch

when (x) {
    1 -> print("x == 1")
    2 -> print("x == 2")
    else -> { // 注意这个块
        print("x 不是 1 ,也不是 2")
    }
}
​
​
when (x) {
    0, 1 -> print("x == 0 or x == 1")
    else -> print("otherwise")
}
​
​
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
}
​
​
when {
    x.isOdd() -> print("x is odd")
    x.isEven() -> print("x is even")
    else -> print("x is funny")
}

for循环

// 迭代器
for (item in collection) print(item)
​
for (item: Int in ints) {
    // ……
}
​
// list
for (i in array.indices) {
    print(array[i])
}
​
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]}")
    }
}

在循环中 Kotlin 支持传统的 break 和 continue 操作符。 return 允许我们从外层函数返回, 从 lambda 表达式中返回,我们必须给它加标签并用以限制 return。

// return结束整个foo
fun foo() {
    ints.forEach {
        if (it == 0) return
        print(it)
    }
}
​
// return结束forEach
fun foo() {
    ints.forEach lit@ {
        if (it == 0) return@lit
        print(it)
    }
}
​
// 函数名也是一个标签
fun foo() {
    ints.forEach {
        if (it == 0) return@forEach
        print(it)
    }
}

当要返一个回值的时候,解析器优先选用标签限制的 return

return@a 1

2.10、类

class Baidu {
    var name: String = "百度"
    var url: String = "www.baidu.com"
    var city: String = "北京"
}
​
val site = Runoob()
println(site.name)
​
// constructor主构造器,这个关键字可以省略
class Person constructor(firstName: String) {}

getter 和 setter 都是可选

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

实例

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

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

二级构造函数

class Person { 
    constructor(parent: Person) {
        parent.children.add(this) 
    }
}
​
// this调用主构造函数的name
class Person(val name: String) {
    constructor (name: String, age:Int) : this(name) {
        // 初始化...
    }
}

abstract抽象类

如果一个类要被继承,可以使用 open 关键字进行修饰。

open class Base {
    open fun f() {}
}
​
abstract class Derived : Base() {
    override abstract fun f()
}

内部类使用 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)   // 内部类可以引用外部类的成员,例如:成员属性
}

interface 与 匿名内部类

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("对象表达式创建匿名内部类的实例")
        }
    })
}

类的修饰符

abstract    // 抽象类  
final       // 类不可继承,默认属性
enum        // 枚举类
open        // 类可继承,类默认是final的
annotation  // 注解类private    // 仅在同一个文件中可见
protected  // 同一个文件中或子类可见
public     // 所有调用的地方都可见
internal   // 同一个模块中可见

属性重写使用 override 关键字

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

扩展函数

class User(var name:String)
​
/**扩展函数**/
fun User.Print(){
    print("用户名 $name")
}
​
fun main(arg:Array<String>){
    var user = User("Runoob")
    user.Print()
}

伴生对象的扩展

class MyClass {
    companion object { }  // 将被称为 "Companion"
}
​
fun MyClass.Companion.foo() {
    println("伴随对象的扩展函数")
}
​
val MyClass.Companion.no: Int
    get() = 10fun main(args: Array<String>) {
    println("no:${MyClass.no}")
    MyClass.foo()
}

数据类,声明一个密封类,使用 data 修饰类

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

密封类,声明一个密封类,使用 sealed 修饰类

sealed class Expr
data class Const(val number: Double) : Expr()
data class Sum(val e1: Expr, val e2: Expr) : Expr()
object NotANumber : Expr()
​
fun eval(expr: Expr): Double = when (expr) {
    is Const -> expr.number
    is Sum -> eval(expr.e1) + eval(expr.e2)
    NotANumber -> Double.NaN
}

泛型

class Box<T>(t: T) {
    var value = t
}
val box: Box<Int> = Box<Int>(1)
// 或者
val box = Box(1) // 编译器会进行类型推断,1 类型 Int,所以编译器知道我们说的是 Box<Int>。
​
​
fun <T> boxIn(value: T) = Box(value)
​
// 以下都是合法语句
val box4 = boxIn<Int>(1)
val box5 = boxIn(1)     // 编译器会进行类型推断// Comparable上约束
fun <T : Comparable<T>> sort(list: List<T>) {
    // ……
}
​
​
​
// 使用 out 使得一个类型参数协变
// 定义一个支持协变的类
class Runoob<out A>(val a: A) {
    fun foo(): A {
        return a
    }
}
​
fun main(args: Array<String>) {
    var strCo: Runoob<String> = Runoob("a")
    var anyCo: Runoob<Any> = Runoob<Any>("b")
    anyCo = strCo
    println(anyCo.foo())   // 输出 a
}

对象表达式

// 通过对象表达式实现一个匿名内部类的对象用于方法的参数中
window.addMouseListener(object : MouseAdapter() {
    override fun mouseClicked(e: MouseEvent) {
        // ...
    }
    override fun mouseEntered(e: MouseEvent) {
        // ...
    }
})
​
// 对象可以继承于某个基类,或者实现其他接口
open class A(x: Int) {
    public open val y: Int = x
}
​
interface B {……}
​
val ab: A = object : A(1), B {
    override val y = 15
}

以上是Kotlin的基础语言的学习,更多进阶Kotlin的学习可以前往

传送直达↓↓↓ :link.juejin.cn/?target=htt…

我的第一个Kotlin程序

为了激起您的学习程序,来尝试一下第一个Kotlin程序吧

fun main(args: Array<string>) {
    println("Hello, World!")
}