Kotlin简介
- 来自于著名的IDE IntelliJ IDEA(Android Studio基于此开发) 软件开发公司 JetBrains(位于东欧捷克)
- 起源来自JetBrains的圣彼得堡团队,名称取自俄罗斯圣彼得堡附近的一个小岛(Kotlin Island)
- 一种基于JVM的静态类型编程语言,2017年谷歌I/O大会确定Kotlin为Android的官方语言
Kotlin应用不同领域
- Kotlin-Script脚本编写
- Kotlin-Android项目开发
- Kotlin-JavaScript前端项目开发
- Kotlin-SpringBoot服务端项目开发
- Kotlin-Native项目开发
Kotlin开发环境
- 需要在IDE中安装Kotlin插件;Android Studio3.0以上
Kotlin的优点
- 简洁(不用判断NullPointException,不需要写分号等)
- 100% 兼容 Java
- 类型自动转换并使用
定义变量
val a: Int = 1 // 显式标明类型,立即赋值
val b = 2 // 自动推断出 `Int` 类型
var c: Int // 如果没有初始值类型不能省略
c = 3 // 明确赋值
var和val的区别
- var是一个可变变量,这种声明变量的方式和java中声明变量的方式一样。
- val是一个只读变量,这种声明变量的方式相当于java中的final变量,以后不能被改变。
var name = "我是可改变的"
println(name)
name = "我真的是可改变"
println(name)
val finalValue = "我是不可改变的";
println(finalValue);
类定义
- 在Kotlin中所有类都有一个共同的超类
Any
//类定义,继承类和实现接口
class FeedBackActivity : NativeBaseActivity(), View.OnLongClickListener, BitmapUtil.SaveImageCall {
}
- 创建类的实例
val invoice = Invoice()
val customer = Customer("Joe Smith")
//注意 Kotlin 并没有 new 关键字。
函数定义
Kotlin 中的函数使用 fun 关键字声明,参数即 name: type。参数用逗号隔开
fun double(x: Int): Int {
return 2 * x
}
- Int 返回类型可以省略
fun sum(a: Int, b: Int): Int {
return a + b
}
也可以
fun sum(a: Int, b: Int) = a + b
- 减少方法重载
//支持默认参数值,减少方法重载
fun showToast(message: String, duration:Int = Toast.LENGTH_LONG) {
Toast.makeText(this, message, duration).show()
}
//调用方式:没有默认值的参数,调用时,必须填写
showToast("toast");
showToast("toast", Toast.LENGTH_LONG);
- main方法比较
//Java
public static void main(String[] args){
}
//Kotlin
fun main(args:Array<String>){
}
主次构造函数
在Kotlin中的一个类可以有一个主构造函数和一个或多个次构造函数
- 主构造函数:带有类名的为主构造函数(只有一个)
- 主构造函数不能包含任何的代码。初始化的代码可以放到以 init 关键字作为前缀的初始化块
- 主构造函数中声明的属性可以是可变的(var)或只读的(val)
//如果构造函数有注解或可见性修饰符,这个 constructor 关键字是必需的,并且这些修饰符在constructor前面:
class Customer public @Inject constructor(name: String) { …… }
//无修饰可不写constructor关键字
class Customer (name: String) {
var a :Int = 1
init{……}
}
- 次构造函数:不带类名并且有constructor关键字修饰的函数为次构造函数(可以一个或多个),并且只能存在主构造函数代码块之内
//如果类有一个主构造函数,每个次构造函数需要委托给主构造函数, 可以直接委托或者通过别的次构造函数间接委托。委托到同一个类的另一个构造函数用 this 关键字即可:
class Person(val name: String) {
constructor(name: String, parent: Person) : this(name) {
parent.children.add(this)
}
}
- 无参构造函数:
- 如果没有构造函数,将会默认一个无参数构造函数
- 如果主构造函数的所有的参数都有默认值,编译器会生成一个额外的无参构造函数,它将使用默认值。
//如构造函数为私有,需用private修饰
class DontCreateMe public constructor () {
}
class Customer(val customerName: String = ""){}
函数调用
val result = double(2)
Sample().foo() // 创建类 Sample 实例并调用 foo
字符串模板
- 字符串可以包含模板表达式,以$开始
val book = Book("Thinking In Java", 59.0f, "Unknown")
val extraValue = "extra"
Log.d("MainActivity", "book.name = ${book.name}; book.price=${book.price};extraValue=$extraValue")
区间
区间表达式由具有操作符形式 .. 的 rangeTo 函数辅以 in 和 !in 形成。
if (i in 1..10) { // 等同于 1 <= i && i <= 10
println(i)
}
//顺序
for (i in 1..4) print(i) // 输出“1234”
for (i in 4..1) print(i) // 什么都不输出
//倒序
for (i in 4 downTo 1) print(i) // 输出“4321”
//要创建一个不包括其结束元素的区间,可以使用 until 函数:
for (i in 1 until 10) { // i in [1, 10) 排除了 10
println(i)
}
//能否以不等于 1 的任意步长迭代数字? 当然没问题, step() 函数有助于此:每循环到第二个元素就剔除
for (i in 1..4 step 2) print(i) // 输出“13”
for (i in 4 downTo 1 step 2) print(i) // 输出“42”
控制流:if、when、for、while
if表达式
if和Java用法一致
val max = if (a > b) a else b
when表达式
when它能完全取代switch/case,也可以用来取代 if-else if链,并且还有很多新的特性。
如果其他分支都不满足条件将会求值else分支。 如果 when 作为一个表达式使用,则必须有 else 分支
, 除非编译器能够检测出所有的可能情况都已经覆盖了。
//分支条件可以是:Int,区间,方法,字符串,对象等
when (x) {
0, 1 -> print("x == 0 or x == 1")
in 2 -> print("x == 2")
in 3..8 -> print("x == 3..8")
parseInt(s)-> print("parseInt")
is String -> print("x is String")
else -> print("otherwise")
}
fun hasPrefix(x: Any) = when(x) {
is String -> x.startsWith("prefix")//智能转换
else -> false
}
//when 也可以用来取代 if-else if链。 如果不提供参数,所有的分支条件都是简单的布尔表达式,而当一个分支的条件为真时则执行该分支:
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) {
// ……
}
for (i in 1..3) {
println(i)//输出“123”
}
for (i in 6 downTo 0 step 2) {
println(i)//输出“6420”
}
//如果想索引遍历,可以通过indices函数
for (i in array.indices) {
println(array[i])
}
//或者你可以用库函数 withIndex:
for ((index, value) in array.withIndex()) {
println("the element at $index is $value")
}
//输出:
the element at 0 is a
the element at 1 is b
the element at 2 is c
While 循环
while 和 do..while 照常使用,省略
Kotlin 有三种结构化跳转表达式:
- return,默认从最直接包围它的函数或者匿名函数返回。
- break,终止最直接包围它的循环。
- continue,继续下一次最直接包围它的循环。
特殊符号?和!!
?:表示当前是否对象可以为空
!!: 表示当前对象不为空的情况下执行
private var cloth_Rv: RecyclerView ?= null
cloth_Rv!!.setHasFixedSize(true)
可见性修饰符
类、对象、接口、构造函数、方法、属性和它们的 setter 都可以有 可见性修饰符。 在 Kotlin 中有这四个可见性修饰符:private、 protected、 internal 和 public。 如果没有显式指定修饰符的话,默认可见性是 public
- internal —— 能见到类声明的 本模块内 的任何客户端都可见其 internal 成员
- 其它和Java一样
重要关键字
Any
在Kotlin中所有类都有一个共同的超类Any
,Any并不是Object
open
- 修饰类:表示能被继承
- 修饰方法:表示需要重写
final、open、abstract、override对比
修饰符 | 相应类的成员 | 注解 |
---|---|---|
final | 不能被重写 | 在kotlin中默认所有的方法和类都是final属性 |
open | 可以被重写 | 需要被明确指出 |
abstract | 必须要重写 | 不能被实例化,默认具有open属性 |
override | 覆写超类的方法 | 如果没有被指定为final,则默认具有open属性 |
companion 伴生对象
//可以省略Factory
class MyClass {
companion object Factory {
fun create(): MyClass = MyClass()
}
}
val instance = MyClass.create()
内部类和匿名内部类
- 内部类
//如果需要调用成员变量,需要用inner修饰内部类
class Outer {
private val bar: Int = 1
inner class Inner {
fun foo() = bar
}
}
val demo = Outer().Inner().foo() // == 1
- 匿名内部类
//匿名内部类
textView.setOnClickListener(object : View.OnClickListener {
override fun onClick(v: View?) {
//...
}
})
扩展
函数扩展可以让你对任意类进行扩展,而不用继承等等复杂的操作。
对参数的解释:
- Context:表示函数的接收者,也就是函数扩展的对象
- . :扩展函数修饰符
- toast:扩展函数的名称或者属性名称
扩展函数
fun Context.showToast(content: String, duration: Int = Toast.LENGTH_SHORT): Toast {
val toast = Toast.makeText(MyApplication.context, content, duration)
toast.show()
return toast
}
这样只要是Context的子类,任何地方都可以调用Toast了
扩展属性
var View.padLeft: Int
set(value) {
setPadding(value, paddingTop, paddingRight, paddingBottom)
}
get() {
return paddingLeft
}
//调用 textView.padLeft = 16
Any扩展函数
apply
- apply 是 Any 的扩展函数,因而所有类型都能调用。
- apply 接受一个lambda表达式作为参数,并在apply调用时立即执行,apply返回原来的对象。
- apply 主要作用是将多个初始化代码链式操作,提高代码可读性。
val task = Runnable { println("Running") }
val thread = Thread(task)
thread.setDaemon(true)
thread.start()
以上代码可以简化为:
val task = Runnable { println("Running") }
Thread(task).apply { setDaemon(true) }.start()
如有问题欢迎留言,感谢支持和关注。