kotlin 是用于現(xiàn)代多平臺(tái)應(yīng)用的靜態(tài)編程語言,可以與 Java? 和 Android? 100% 可互操作。
基本語法
表達(dá)式和語句
表達(dá)式:有值,并且能作為另一個(gè)表達(dá)式的一部分使用玩裙。
語句:總是包含著它的代碼塊中的頂層元素,并且沒有自己的值段直。
當(dāng)函數(shù)體是由單個(gè)表達(dá)式構(gòu)成時(shí)吃溅,可以用這個(gè)表達(dá)式作為完整的函數(shù)體,并且去掉花括號(hào)和 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 聲明的變量不能在初始化之后再次賦值
這種變量的值可以改變鸯檬,但是它的類型卻是改變不了的
屬性
當(dāng)聲明屬性的時(shí)候决侈,就聲明了對(duì)應(yīng)的訪問器(只讀屬性有一個(gè) 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("斷電");
}
循環(huán)與迭代
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 檢查機(jī)制
//類型后面加?表示可為空
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 "一年級(jí)")
}
函數(shù)
定義一個(gè)函數(shù)
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)
}
命名參數(shù)
- 增加函數(shù)的可讀性
- 以想要的順序指定需要的參數(shù)
可以這樣調(diào)用上面的函數(shù)
val list = listOf(1, 2, 3)
joinToString(end = "}", pre = "{", sep = ",", collection = list)
joinToString(list, end = "}", pre = "{", sep = ",")
如果在調(diào)用一個(gè)函數(shù)時(shí)喧务,指明了一個(gè)參數(shù)的名稱赖歌,那它之后的所有參數(shù)都要表明名稱枉圃。
當(dāng)調(diào)用 Java 函數(shù)時(shí),不能使用命名參數(shù)庐冯。
默認(rèn)參數(shù)
可以避免創(chuàng)建重裝函數(shù)
fun <T> joinToString(collection: Collection<T>, sep: String = ",", pre: String = "{", end: String = "}") {
... ...
}
頂層函數(shù)和屬性
擴(kuò)展函數(shù)
添加擴(kuò)展函數(shù)
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");
- 擴(kuò)展函數(shù)不存在重寫
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
*/
擴(kuò)展屬性
//擴(kuò)展屬性
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)
// }
可變參數(shù)
fun varargFun(vararg args: Int) {
args.forEach {
println("var =$it")
}
}
fun testDemo(args: ArrayList<String>) {
//將參數(shù)打包成一個(gè)數(shù)組,傳參數(shù)時(shí)需要使用*解包
val ints = intArrayOf(2, 4, 6, 7)
varargFun(*ints)
}
中綴調(diào)用
val pair0 = 1.to("one")
val pair1 = 3 to "three"
val hashMap = HashMap<Int, String>()
hashMap.plus(pair0)
hashMap.plus(pair1)
定義中綴調(diào)用孽亲,需要使用 infix 修飾符來標(biāo)記
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}")
}
局部函數(shù)
可以在函數(shù)中嵌套這些提取的函數(shù),局部函數(shù)定義方式和普通函數(shù)是相同的
正則表達(dá)式
println("23.1|21-6.AB".split("[.|-]".toRegex()))
//第一組(.+)包含最后一個(gè)斜線之前的子串
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")
}
}
對(duì)象
接口
可以包含默認(rèn)實(shí)現(xiàn)的抽象方法
訪問性修飾符
open展父、final 和 abstract 這三個(gè)訪問修飾符都 只適用于類返劲,不能用在接口。
- open:用于聲明一個(gè)類可以被繼承栖茉,或者方法可以被子類重寫篮绿。
- final:不允許類被繼承,或者不允許方法被重寫吕漂。
- abstract:聲明抽象類搔耕,或者抽象類中的抽象方法。
- 當(dāng)我們需要重寫方法時(shí)痰娱,必須加上 override 修飾符弃榨。
可見性修飾符
修飾符 | 類成員 | 頂層聲明 |
---|---|---|
public | 所有地方可見 | 所有地方可見 |
internal | 模塊中可見 | 模塊中可見 |
protected | 子類中可見 | --- |
private | 類中可見 | 文件中可見 |
內(nèi)部類和嵌套類
在 Kotlin 中,如果我們像 Java 一樣梨睁,在一個(gè)類的內(nèi)部定義一個(gè)類鲸睛,那么它并不是一個(gè) 內(nèi)部類,而是 嵌套類坡贺,區(qū)別在于嵌套類不會(huì)持有外部類的引用官辈,也就是說它實(shí)際上是一個(gè)靜態(tài)內(nèi)部類。
class Outer {
inner class Inner {
fun getOutReference(): Outer = this@Outer
}
}
如果要把它嵌套類變成一個(gè) 內(nèi)部類 來持有一個(gè)外部類的引用的話需要使用 inner 修飾符遍坟,并且訪問外部類時(shí)拳亿,需要使用 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)
}
構(gòu)造方法
主構(gòu)造方法:主要而簡潔的初始化類的方法,并且在 類體外部聲明愿伴。
從構(gòu)造方法:在類體內(nèi)部聲明肺魁。
class User constructor(name: String) {
val userName: String
init {
userName = name
}
}
constructor:用來開始一個(gè)主構(gòu)造方法和從構(gòu)造方法的聲明。
init:引入一個(gè)初始化塊語句隔节,這種語句塊包含了在類被創(chuàng)建時(shí)執(zhí)行的代碼鹅经,并會(huì)與主構(gòu)造方法一起使用,因?yàn)橹鳂?gòu)造方法有語法限制怎诫,這就是為什么要使用初始化語句塊的原因瘾晃。
如果主構(gòu)造方法沒有注解或可見性修飾符,可以取消 constructor 關(guān)鍵字幻妓。
class User(val name: String)
必須顯示地調(diào)用父類的構(gòu)造方法蹦误,即使它沒有任何的參數(shù)
open class User(val name: String)
class TimeUser(name: String) : User(name) {
fun printUserInfo() = print("user name =${this.name}")
}
從構(gòu)造方法 constructor
子類調(diào)用父類的從構(gòu)造方法:super
子類調(diào)用自己的另一個(gè)構(gòu)造方法:this
數(shù)據(jù)類
使用 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
以一句話來定義一個(gè)類和一個(gè)該類的變量
object Singleton {
var name: String = "singleton"
var age: Int = 0
}
fun testSingleTon() {
println("${Singleton.name}的年齡${Singleton.age}")
}
application 實(shí)現(xiàn)單例
class App : Application() {
companion object {
lateinit var instance: App //延遲加載,不需要初始化,否則需要在構(gòu)造函數(shù)初始化
private set
}
override fun onCreate() {
super.onCreate()
instance = this
}
}
-
創(chuàng)建單例 object
class LazySingleton private constructor(){ companion object { val instance: LazySingleton by lazy { LazySingleton() } } }
-
伴生對(duì)象 companion
伴生對(duì)象所在的類被加載强胰,伴生對(duì)象被初始化尚镰,與 Java 靜態(tài)成員一樣
工廠方法和靜態(tài)成員的實(shí)現(xiàn)
使用伴生對(duì)象來實(shí)現(xiàn)工廠方法
如果你需要寫一個(gè)在沒有類實(shí)例的情況下,調(diào)用但是需要訪問類內(nèi)部的函數(shù),可以將其寫成那個(gè)類中的 對(duì)象聲明的成員.
在類中定義的對(duì)象之一可以使用一個(gè)特殊的關(guān)鍵字來標(biāo)記 companion哪廓,如果這樣做狗唉,就獲得了直接 通過容器類名稱來訪問這個(gè)對(duì)象的方法和屬性的能力,不再需要顯示地指明對(duì)象的名稱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")) }
-
在伴生對(duì)象中實(shí)現(xiàn)接口
就像其它對(duì)象聲明一樣涡真,伴生對(duì)象也可以實(shí)現(xiàn)接口分俯,可以將包含它的類的名字當(dāng)做實(shí)現(xiàn)了該接口的對(duì)象實(shí)例來使用。
class Response(val name: String) { companion object } fun Response.Companion.toJson(response: Response) = "name : ${response.name}" fun testResponse() { Response.Companion.toJson(Response("andy")) }
對(duì)象表達(dá)式
object 關(guān)鍵字不僅能夠用來表明單例式的對(duì)象哆料,還能用來聲明匿名對(duì)象缸剪,它替代了 Java 中匿名內(nèi)部類的用法。
lambda 表達(dá)式
btnLogin.setOnClickListener { v ->
val id = v.id
}
btnLogin.setOnClickListener {
}
如果 lambda 剛好是 函數(shù)或者屬性的委托东亦,可以用 成員引用 替換杏节。
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))
}
語法
一個(gè) Lambda 表達(dá)式把一小段行為進(jìn)行編碼,你能把它 當(dāng)做值到處傳遞典阵,它可以被獨(dú)立地聲明并存儲(chǔ)到一個(gè)變量中奋渔,但是最常見的還是直接聲明它并傳遞給函數(shù)
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
}
}
方法參數(shù)
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)
}
存儲(chǔ)到變量中
val sum = { x: Int, y: Int -> x + y }
println(sum(1, 3))
直接調(diào)用 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 表達(dá)式可以包含更多的語句,最后一個(gè)表達(dá)式就是 lambda 的結(jié)果
val total = { x: Int, y: Int ->
println("start count")
x + y
}
println(total(1, 4))
bookList.forEach {
print("${it.name} has ${it.count}")
}
引用頂層函數(shù)
直接以:開頭壮啊,成員引用::salute 被當(dāng)作實(shí)參傳遞給庫函數(shù) run
fun salute() = print("hello")
fun main1(args: ArrayList<String>) {
run(::salute)
}
存儲(chǔ)或者延期執(zhí)行創(chuàng)建類實(shí)例的動(dòng)作
val createBook = ::TimeBook
println(createBook("tommao", 12))
引用擴(kuò)展函數(shù)
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})
** 知識(shí)索引 **
kotlin 語言中文站