一、什么是kotlin?



Kotlin,现代多平台静态编程语言。由JetBranis开发,于2012年2月发布v1.0版本。2017年成为android的官方支持的开发语言。
多平台,可以编译成java字节码,在jvm上运行,也可以编程js在浏览器上运行。


静态,可以静态检测常见异常,比如NullPointerException。
二、为什么要使用kotlin?
1、简洁
大大减少了代码行的数量。

2、安全
避免了空指针异常。

3、互操作性
充分利用 JVM、Android 和浏览器的现有库。


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
}
网友评论