kotlin 是用于现代多平台应用的静态编程语言,可以与 Java™ 和 Android™ 100% 可互操作。
基本语法
表达式和语句
表达式:有值,并且能作为另一个表达式的一部分使用。
语句:总是包含着它的代码块中的顶层元素,并且没有自己的值。
当函数体是由单个表达式构成时,可以用这个表达式作为完整的函数体,并且去掉花括号和 return 语句
fun max(x: Int, y: Int): Int {
return if (x > y) x else y
}
fun min(x: Int, y: Int) = if (x > y) y else x
可变变量和不可变变量 : var 和 val
使用 val 声明的变量不能在初始化之后再次赋值
这种变量的值可以改变,但是它的类型却是改变不了的
属性
当声明属性的时候,就声明了对应的访问器(只读属性有一个 gettter,而可变属性则有 getter/setter)
class Person(
val name: String,
var isMarried: Boolean
)
fun personFun() {
val person = Person("andy", true)
print("${person.name}是不是${person.isMarried}")
}
class Rectangle(var width: Int, var height: Int) {
val isSquare = width == height
}
fun main(args: ArrayList<String>) {
personFun()
val rectangle = Rectangle(12, 12)
print(rectangle.isSquare)
}
field
class LengthCounter {
var str: String = ""
set(value) {
if (value == "") {
println("no value")
} else {
field = value
}
}
var counter = 0
private set
fun addWord(word: String) {
str += word
counter += word.length
}
}
枚举
enum class Color {
RED, ORANGE, GREEN
}
enum class ColorValue(private val r: Int, private val g: Int, private val b: Int) {
RED(255, 0, 0), ORANGE(255, 265, 0), GREEN(0, 255, 0);
fun rgb() = (r * 256 + g) * 256 + b
}
fun main(args: ArrayList<String>) {
print(Color.RED)
print(ColorValue.GREEN)
print(ColorValue.GREEN.rgb())
}
enum class DeviceStatus(val value: String) {
POWER("来电"),
NO_POWER("断电");
}
循环与迭代
fun forFun(start: Int, end: Int) {
for (i in start..end) {
print(i)
}
for (i in end downTo start step 2) {
print(i)
}
for (i in start until end) {
print(i)
}
//map集合的存取
val hashMap = HashMap<Char, String>()
for (c in 'A'..'Z') {
val binaryString = Integer.toBinaryString(c.toInt())
hashMap[c] = binaryString
}
for ((k, v) in hashMap) {
print("key = $k, value = $v")
}
}
@Test
fun testForeach() {
//continue
(1..20).forEach {
println(it)
if (it >= 10) {
return@forEach
}
println("=$it")
}
//break
run outside@{
(1..20).forEach inside@{
println(it)
if (10 <= it) return@outside
println("=$it")
}
}
}
异常处理
fun verifyNum(str: String) = {
val num = try {
Integer.parseInt(str)
} catch (e: NumberFormatException) {
null
}
print(num)
}
NULL 检查机制
//类型后面加?表示可为空
var age: String? = "23"
//抛出空指针异常
val ages = age!!.toInt()
//不做处理返回 null
val ages1 = age?.toInt()
//age为空返回-1
val ages2 = age?.toInt() ?: -1
集合
fun collectionDemo() {
val arrayListOf = arrayListOf("andy", "tom", "json")
val hashMapOf = hashMapOf<String, String>("name" to "andy", "grade" to "一年级")
}
函数
定义一个函数
fun <T> joinToString(collection: Collection<T>, sep: String, pre: String, end: String) {
val sb = StringBuilder(pre)
for ((index, value) in collection.withIndex()) {
if (index > 0) {
sb.append(sep)
}
sb.append(value)
}
sb.append(end)
print(sb)
}
命名参数
- 增加函数的可读性
- 以想要的顺序指定需要的参数
可以这样调用上面的函数
val list = listOf(1, 2, 3)
joinToString(end = "}", pre = "{", sep = ",", collection = list)
joinToString(list, end = "}", pre = "{", sep = ",")
如果在调用一个函数时,指明了一个参数的名称,那它之后的所有参数都要表明名称。
当调用 Java 函数时,不能使用命名参数。
默认参数
可以避免创建重装函数
fun <T> joinToString(collection: Collection<T>, sep: String = ",", pre: String = "{", end: String = "}") {
... ...
}
顶层函数和属性
扩展函数
添加扩展函数
fun Context.toast(message: CharSequence) = Toast.makeText(this, message, Toast.LENGTH_LONG).show()
fun String.getLastChar(): Char = this[this.length - 1]
//在kotlin中使用
val lastChar = "andy".getLastChar()
print(lastChar)
//在java类中使用
char lastChar = KotlinDemoKt.getLastChar("andy");
- 扩展函数不存在重写
open class MyView {
open fun click() {
println("this is button")
}
}
class MyButton : MyView() {
override fun click() {
println("this is button")
}
}
fun MyView.showName() = println("my view")
fun MyButton.showName() = println("my button")
fun testDemo() {
val myButton = MyButton()
myButton.showName()
myButton.click()
val aBtn: MyView = MyButton()
aBtn.showName()
aBtn.click()
}
/*
my button
this is button
my view
this is button
*/
扩展属性
//扩展属性
var TextView.leftMargin:Int
get():Int {
return (layoutParams as ViewGroup.MarginLayoutParams).leftMargin
}
set(value) {
(layoutParams as ViewGroup.MarginLayoutParams).leftMargin=value
}
//================//
var StringBuilder.lastChar: Char
get() = this[length - 1]
set(value) = this.setCharAt(length - 1, value)
// set(value) {
// this.setCharAt(length - 1, value)
// }
可变参数
fun varargFun(vararg args: Int) {
args.forEach {
println("var =$it")
}
}
fun testDemo(args: ArrayList<String>) {
//将参数打包成一个数组,传参数时需要使用*解包
val ints = intArrayOf(2, 4, 6, 7)
varargFun(*ints)
}
中缀调用
val pair0 = 1.to("one")
val pair1 = 3 to "three"
val hashMap = HashMap<Int, String>()
hashMap.plus(pair0)
hashMap.plus(pair1)
定义中缀调用,需要使用 infix 修饰符来标记
class Student(val name: String, val isMarried: Boolean)
infix fun String.factory(isMarried: Boolean) = Student(this, isMarried)
fun testInFix() {
val andy: Student = "andy" factory true
println("name = ${andy.name},isMarried = ${andy.isMarried}")
println(andy.isMarried)
val tom = "Tom" factory false
println("name = ${tom.name},isMarried = ${tom.isMarried}")
}
局部函数
可以在函数中嵌套这些提取的函数,局部函数定义方式和普通函数是相同的
正则表达式
println("23.1|21-6.AB".split("[.|-]".toRegex()))
//第一组(.+)包含最后一个斜线之前的子串
fun parsePath(path: String) {
val dir = path.substringBeforeLast("/")
val fileFullName = path.substringAfterLast("/")
val fileName = fileFullName.substringBefore(".")
val ext = fileFullName.substringAfter(".")
println("dir = $dir ,fileName = $fileName ,ext = $ext")
}
fun parsePathByRegex(path: String) {
var regex = """(.+)/(.+)\.(.+)""".toRegex()
val entire = regex.matchEntire(path)
if (entire != null) {
val (dir, fileName, ext) = entire.destructured
println("dir = $dir ,fileName = $fileName ,ext = $ext")
}
}
对象
接口
可以包含默认实现的抽象方法
访问性修饰符
open、final 和 abstract 这三个访问修饰符都 只适用于类,不能用在接口。
- open:用于声明一个类可以被继承,或者方法可以被子类重写。
- final:不允许类被继承,或者不允许方法被重写。
- abstract:声明抽象类,或者抽象类中的抽象方法。
- 当我们需要重写方法时,必须加上 override 修饰符。
可见性修饰符
修饰符 | 类成员 | 顶层声明 |
---|---|---|
public | 所有地方可见 | 所有地方可见 |
internal | 模块中可见 | 模块中可见 |
protected | 子类中可见 | --- |
private | 类中可见 | 文件中可见 |
内部类和嵌套类
在 Kotlin 中,如果我们像 Java 一样,在一个类的内部定义一个类,那么它并不是一个 内部类,而是 嵌套类,区别在于嵌套类不会持有外部类的引用,也就是说它实际上是一个静态内部类。
class Outer {
inner class Inner {
fun getOutReference(): Outer = this@Outer
}
}
如果要把它嵌套类变成一个 内部类 来持有一个外部类的引用的话需要使用 inner 修饰符,并且访问外部类时,需要使用 this@{外部类名}的方式
密封类 sealed
sealed class Expr {
class Num(val value: Int) : Expr()
class Sum(val width: Expr, val height: Expr) : Expr()
}
fun eval(expr: Expr): Int =
when (expr) {
is Expr.Num -> expr.value
is Expr.Sum -> eval(expr.width) + eval(expr.height)
}
构造方法
主构造方法:主要而简洁的初始化类的方法,并且在 类体外部声明。
从构造方法:在类体内部声明。
class User constructor(name: String) {
val userName: String
init {
userName = name
}
}
constructor:用来开始一个主构造方法和从构造方法的声明。
init:引入一个初始化块语句,这种语句块包含了在类被创建时执行的代码,并会与主构造方法一起使用,因为主构造方法有语法限制,这就是为什么要使用初始化语句块的原因。
如果主构造方法没有注解或可见性修饰符,可以取消 constructor 关键字。
class User(val name: String)
必须显示地调用父类的构造方法,即使它没有任何的参数
open class User(val name: String)
class TimeUser(name: String) : User(name) {
fun printUserInfo() = print("user name =${this.name}")
}
从构造方法 constructor
子类调用父类的从构造方法:super
子类调用自己的另一个构造方法:this
数据类
使用 data 修饰符生成通用方法
copy
val client = Client("tom", 12)
println(client.toString())
val copyClient = client.copy("andy")
println(copyClient)
委托
package cn.timeface
import kotlin.properties.ReadOnlyProperty
import kotlin.reflect.KProperty
/**
* Created by zhangsheng on 2017/10/28.
*/
class ResourceID {
val image_id: String = "101"
val text_id: String = "102"
}
class ResourceLoader(id: ResourceID) {
private val d: ResourceID = id
operator fun provideDelegate(thisRef: MyUI, prop: KProperty<*>): ReadOnlyProperty<MyUI, String> {
if (checkProperty(prop.name)) {
return DellImpl(d)
} else {
throw Exception("Error ${prop.name}")
}
}
private fun checkProperty(name: String): Boolean {
return name == "image" || name == "text"
}
}
class DellImpl(d: ResourceID) : ReadOnlyProperty<MyUI, String> {
val id: ResourceID = d
override fun getValue(thisRef: MyUI, property: KProperty<*>): String {
return if (property.name == "image")
property.name + " " + id.image_id
else
property.name + " " + id.text_id
}
}
fun bindResource(id: ResourceID): ResourceLoader {
return ResourceLoader(id)
}
class MyUI {
val image by bindResource(ResourceID())
val text by bindResource(ResourceID())
}
fun main(args: Array<String>) {
try {
val ui = MyUI()
println(ui.image)
println(ui.text)
} catch (e: Exception) {
println(e.message)
}
}
object
以一句话来定义一个类和一个该类的变量
object Singleton {
var name: String = "singleton"
var age: Int = 0
}
fun testSingleTon() {
println("${Singleton.name}的年龄${Singleton.age}")
}
application 实现单例
class App : Application() {
companion object {
lateinit var instance: App //延迟加载,不需要初始化,否则需要在构造函数初始化
private set
}
override fun onCreate() {
super.onCreate()
instance = this
}
}
-
创建单例 object
class LazySingleton private constructor(){ companion object { val instance: LazySingleton by lazy { LazySingleton() } } }
-
伴生对象 companion
伴生对象所在的类被加载,伴生对象被初始化,与 Java 静态成员一样
工厂方法和静态成员的实现
使用伴生对象来实现工厂方法
如果你需要写一个在没有类实例的情况下,调用但是需要访问类内部的函数,可以将其写成那个类中的 对象声明的成员.
在类中定义的对象之一可以使用一个特殊的关键字来标记 companion,如果这样做,就获得了直接 通过容器类名称来访问这个对象的方法和属性的能力,不再需要显示地指明对象的名称class Response(val name: String) { companion object Loader { fun toJson(response: Response) = "name : ${response.name}" } } fun testResponse() { Response.Loader.toJson(Response("andy")) Response.toJson(Response("Tom")) }
-
在伴生对象中实现接口
就像其它对象声明一样,伴生对象也可以实现接口,可以将包含它的类的名字当做实现了该接口的对象实例来使用。
class Response(val name: String) { companion object } fun Response.Companion.toJson(response: Response) = "name : ${response.name}" fun testResponse() { Response.Companion.toJson(Response("andy")) }
对象表达式
object 关键字不仅能够用来表明单例式的对象,还能用来声明匿名对象,它替代了 Java 中匿名内部类的用法。
lambda 表达式
btnLogin.setOnClickListener { v ->
val id = v.id
}
btnLogin.setOnClickListener {
}
如果 lambda 刚好是 函数或者属性的委托,可以用 成员引用 替换。
data class TimeBook(val name: String, val count: Int)
fun testLambda() {
val listOf = listOf(TimeBook("andy", 12), TimeBook("tom", 14))
println(listOf.maxBy { it.count })
println(listOf.maxBy(TimeBook::count))
}
语法
一个 Lambda 表达式把一小段行为进行编码,你能把它 当做值到处传递,它可以被独立地声明并存储到一个变量中,但是最常见的还是直接声明它并传递给函数
class DiagramTest {
@Test
fun testApply() {
val lam1 = lam("hello", { hello(it) })
println(lam1)
val lam2 = lam("hello", {
it + "world"
})
println(lam2)
val testLam = testLam(10, {
101
})
println(testLam)
}
private fun lam(string: String, p: (num: String) -> String): String {
return p(string)
}
private fun hello(string: String): String {
return string + " world"
}
private fun testLam(num: Int, p: () -> Int): Int {
return p() + num
}
}
方法参数
fun functionAbs(x: Int, y: Int, absAction: (Int) -> Int): Int {
return absAction(x) + absAction(y)
}
var absSum: (Int) -> Int = {
Math.abs(it)
}
fun test() {
functionAbs(1, -2, absSum)
}
存储到变量中
val sum = { x: Int, y: Int -> x + y }
println(sum(1, 3))
直接调用 run
fun main(args : ArrayList<String>){
run {
println("hello world")
}
}
joinToString
val toString = listOf.joinToString("==", "[", "]",
transform = { timeBook: TimeBook -> timeBook.name })
println(toString)
@Test
fun testKotlin() {
val listStr = (1..5).joinToString(",") { "$it:$it" }
println(listStr)
//1:1,2:2,3:3,4:4,5:5
val list = arrayListOf<String>()
list.add("8")
list.add("9")
val str = list.joinToString(",") { "${list.indexOf(it)}:$it" }
println(str)
//0:8,1:9
val result = listStr
.split(",".toRegex())
.map { it.split(":")[1] }
.filter { !it.isEmpty() }
println(result)
//1,2,3,4,5
}
包含多条语句
lambda 表达式可以包含更多的语句,最后一个表达式就是 lambda 的结果
val total = { x: Int, y: Int ->
println("start count")
x + y
}
println(total(1, 4))
bookList.forEach {
print("${it.name} has ${it.count}")
}
引用顶层函数
直接以:开头,成员引用::salute 被当作实参传递给库函数 run
fun salute() = print("hello")
fun main1(args: ArrayList<String>) {
run(::salute)
}
存储或者延期执行创建类实例的动作
val createBook = ::TimeBook
println(createBook("tommao", 12))
引用扩展函数
fun TimeBook.hasMore() = count > 0
fun main1(args: ArrayList<String>){
bookList.filter { it.count > 0 }
val hasNext = TimeBook::hasMore
bookList.filter(hasNext)
println(list)
}
also\run\apply\with\let
collections
list to map
val myMap = myList.map { it.name to it.age }.toMap()
val myMap = myList.associateBy({ it.name }, { it.hobbies })
val myMap = myList.associate{ it to it }
//1.
val myMap = mutableMapOf<String, String>()
myList.associateTo(myMap) {it to it}
//2.
val myMap = mutableMapOf<String, User>()
myList.associateByTo(myMap) {it.name}
//3.
val myMap = mutableMapOf<String, Int>()
myList.associateByTo(myMap, {it.name}, {it.age})
** 知识索引 **
kotlin 语言中文站