常量和变量
fun main() { //变量 var a: Int = 2 a = 3 //只读变量,在局部中,和 final 相同 val b = 2 //如果是全局 val x = X() println(x.b) //每次的值都不一样 /** * 长量引用 * 创建的对象在 堆 上 * 对象内部内容可以改变,但是对象不能改变 */ val x1 = X() } /** * 常量 * 只能定义在全局范围 * 只能修饰基本类型 * 必须立即用字变量初始化 * 和 java 中的 static final 基本相同 */ const val b = 2 // 编译时即可确定常量的值,并用值替换调用处 val c: Int //运行时才能确定值 get() { TODO() } class X { //属性 val b: Int get() { return (Math.random() * 100).toInt() } }
分支表达式
fun main() { var c = 4 // if else 表达式 c = if (c == 4) 3 else 9 println(c) //分支,类似于 switch,但是不用写 break when (c) { 0 -> c = 2 1 -> c = 3 else -> c = 20 } //简化 c = when (c) { 0 -> 2 1 -> 3 else -> 20 } //条件转移到分支 var x: Any = "" when { x is String -> x = "哈哈哈" x is Int -> x = 10 else -> x = 90 } //简化 x = when (x) { is String -> "哈哈哈" is Int -> 10 else -> 90 } //when... x = when (val input = readLine()) { null -> "" else -> input.length } //try ... catch 表达式 x = try { 3 / 0 } catch (e: Exception) { e.printStackTrace() 0 } }
运算符
Kt 中支持运算符重载
运算符的范围仅限官方指定的符号
指定的符号
Kt 允许我们为自己的类型提供预定义的一组操作符的实现,这些操作符举要固定的符号表示,如 + * 等。为实现这样的操作符,Kt 为相应的类型提供了一个固定名字的成员函数或者扩展函数。重载操作符需要使用 operator 修饰符标记。
如下:
fun main() { val point = Point(10, 20) println(point - 10) //0 } class Point(val x: Int, val y: Int) { //重载 - 号 operator fun minus(num: Int): Int { return x - num } }
fun main() { val point = Point(10, 20) println(point[0]) //10 println(point[1]) //20 println(point[2]) //java.lang.IndexOutOfBoundsException } class Point(val x: Int, val y: Int) { //重载 get operator fun get(index: Int): Int { return when (index) { 0 -> x 1 -> y else -> throw IndexOutOfBoundsException() } } }
官方中文文档
中缀表达式
fun main() { println("Hello" to "Word") } /** * 中缀表达式 * 必须加 infix 标识 * 只有一个参数,并且是扩展方法 */ infix fun String.rotate(str: String): String { return this + str }
函数的表达式形式
fun main() { println(add(1, 2)) println(add2(2, 3)) } fun add(x: Int, y: Int): Int { return x + y } //如果函数中只有一句或者为一个表达式,可以这样写 fun add2(x: Int, y: Int): Int = x + y
Lambad 表达式
fun main() { /** * 将匿名函数赋值给一个变量 * fun1 是变量名 * 调用 fun1() */ val fun1 = fun() { println("匿名函数") } //Lambad 其实就是匿名函数 val l1 = { println("lambad") } //带参数的 Lambad val l2 = { p: Int -> println("带参数的 Lambad") } // 表达式中最后一行为返回值,可不加 return val l3 = { p: Int -> println(p) "Hello Word" } //表达式中如果只有一个参数,可以用 it 代替 val l4: Function1<Int, Unit> = { println(it) } l4(123) //第二个参数接收一个Lambad 表达式,接收一个 Int 参数,并返回一个 Int 参数 IntArray(2) { i -> 0 } fun3() { x: Int, y: Int -> println("${x + y}") "$x + $y" } } //接收两个 int 类型,返回一个 String 类型的函数 fun fun3(sum: (Int, Int) -> String) { println(sum(2, 3)) } fun fun0() { println("普通函数") }
案例1
实现 equals 和 hashCode
fun main() { val hashSet = hashSetOf<Person>() (0..5).forEach { _ -> hashSet += Person(30, "张三") } println(hashSet.size) //注意:将对象添加到集合后就不要改变对象的数据,否则会造成无法删除,从而引发内存泄露 } class Person(private val age: Int, private val name: String) { override fun equals(other: Any?): Boolean { val o = (other as? Person) ?: return false return age == o.age && name == o.name } override fun hashCode(): Int { return 31 + age * 7 + name.hashCode() } }
案例2
实现 String 的四则运算
fun main() { val value = "HelloWorld" println(value - "World") println(value * 3) println(value / "l") } // - 替换第一个出现的字符串 operator fun String.minus(right: Any?): String = this.replaceFirst(right.toString(), "") // * 链接一个字符串 operator fun String.times(count: Int): String { return (1..count).joinToString(" ") { this } } // / 找出出现多少次 operator fun String.div(right: Any?): Int { val r = right.toString() //根据传入的字符串,从 this 中挨个进行查找 //如 length = 2,那就是 " he , el ,ll ,lo , ow ... " //最后一个参数是表达式,所以可以移到外面 return this.windowed(r.length, 1) { //判断是否相等 it == r }.count { //计数, it } }
总结
常量和变量
定义方式:var / val /const val
常量按类型分类
常量值
常量引用
常量按时期分类
编译器常量
运行时常量
分支表达式
if else
when …
try … catch
运算符
常见的运算符
“+ - * /”
“. < ==”
“ in ”
" get "
" invoke "
运算符的重载
中缀表达式:必须有 infix 标识,是扩展方法,并且只有一个参数
函数的表达式形式:如果函数中只有一句话或者一个表达式,可直接赋值给 函数
Lambad
匿名函数 :本质是匿名函数,匿名函数不能直接使用,需要一个变量来接收,然后调用这个变量就能间接的调用这个匿名函数
写法
类型
类型推断:如果左边定义中已经写了具体的类型声明,后面的实现就可以不用写。反之,后面则需要具体的声明