一、Kotlin基礎
1.資料型別宣告
在Kotlin中要定義一個變數需要使用var關鍵字
//定義了一個可以修改的Int型別變數
var number = 39
如果要定義一個常量可以使用val關鍵字,等價于Java的final關鍵字.
val name = "miku"
//給val定義的常量再次賦值就會提示錯誤
name = "ミク"

在Kotlin中要宣告一個資料型別必須要使用var或者val來定義.
2.資料型別
Kotlin的資料型別分為基本資料型別和參考資料型別.
基本資料型別:Boolean、Number、Char
參考型別:可空型別、Object、陣列型別
Kotlin中的Number型別泛指所有跟數字有關的型別,int、float、double、long
//java.lang.Integr Int--->int
var intNumber:Number = 39
//java.lang.Float Float--->float
var floatNumber:Number = 39.0f
//java.lang.Double Double--->double
var doubleNumber:Number = 39.000000000000000
//java.lang.Long Long--->long
var longNumber:Number = 39L
2.1.Kotlin預定義的基本資料型別
var intType:Int = 39 //int
var shortType:Short = 39 //short
var byteType:Byte = 0 //byte
var boolType:Boolean = true //boolean
var stringType:String = "miku" //String
var floatType:Float = 39f //float
var doubleType:Double = 39.0000000000 //double
var longType:Long = 39L //long
var numberType:Number = 39 //Integr、Float、Double、Long
var charType:Char = '0' //char
字串拼接,通過${}直接參考變數,不再需要引號 + 引號的方式
val name = "komine"
val text = "私の名前は${name}と申します,"
print(text)
2.2.元組
元組是一個固定長度,且不能被修改的資料結構
//二階元組
var person1 = Pair("komin",16)
//三階元組
var person2 = Triple("komine",18,"女")
person2.first //第一個元素的值
person2.second //第二個元素的值
person2.third //第三個元素的值
Kotlin的元組其實就是一個泛型物件的封裝.通過反編譯生成的.class檔案可以看出,二階元組其實是對應Pair類,
三階元組其實是對應Triple類. first、second、third分別對應getFirst()、getSecond()、getThrid()方法.

如果用Java來實作的話差不多就是下面這個樣子,可以看到,元組不過是Kotlin在原始碼階段提供的一種更方便的語法而已.
public class MyPair<First,Second> {
private final First mFirstValue;
private final Second mSecond;
public MyPair(First first, Second second){
this.mFirstValue = https://www.cnblogs.com/komine/p/first;
this.mSecond = second;
}
public First getFirst() {
return mFirstValue;
}
public Second getSecond() {
return mSecond;
}
}
2.3.可空型別
Kotlin定義了一種可以為空的資料型別,只有宣告為可空型別的變數才能將null賦值于它.默認宣告的型別全部都是非空型別.
var str:String? = null //在型別的后面添加?表示該型別可空
print(str?.length) //通過?.方式來訪問可空型別的成員方法或變數,如果str是null則后面的呼叫會回傳null,不會報錯
//如果你明確知道,str在某個時候肯定不為空,可以通過!!操作該變數,但如果str為空則會拋出空指標例外
print(str!!.length)
2.4.陣列
在Kotlin中定義一個陣列非常簡單.呼叫arrayOf()即可創建一個陣列.
var names = arrayOf("miku","rin","luka")
var numbers = arrayOf(16,14,17)
//跟Java一樣,也可以通過[下標]的方式訪問陣列的元素
print(names[0])
//創建一個指定長度的陣列,值為null
var fixedArray = arrayOfNulls<Int>(39)
//創建一個空陣列
var emptyArray = emptyArray<Int>()
2.5.集合
Kotlin的集合分為可變集合和不可變集合.可變集合都是由Mutable開頭的.
可變集合
//MutableList集合,該集合可以包含相同元素
var mutableList = mutableListOf("miku","rin","luka")
//鍵值對,包含Key和Value的集合
var mutableMap = mutableMapOf<String,String>()
var linkedHashMap = linkedMapOf<String,String>() //等價mutableMap
//MutableSet集合,該集合不會出現相同的元素,如果集合已經包含某個值,添加的時候會忽略添加操作
var mutableSet = mutableSetOf<Object>()
var linkedSet = linkedSetOf<String>() //等價mutableSet
不可變集合
//List集合,無法進行添加操作
var list = listOf("miku","rin","luka")
//Map集合,無法進行添加操作
var map = mapOf(Pair("miku",16))
var linkedMap =
//Set集合,無法進行添加操作
var set = setOf<Int>(0,1,2,3,4,5,6,7,8,9)
2.5.1擴展方法
toList() 回傳一個不可變List集合
toMap() 回傳一個不可變的Map集合
toSet() 回傳一個不可變的Set集合
2.5.2集合操作
類似.Net中的Linq查詢
any 判斷集合中是否有滿足條件的元素
var mutableList = mutableListOf("miku","rin","luka")
val result:Boolean = mutableList.any(){
it == "miku" //有一個元素的值為miku
}
all 判斷集合中的所有元素是都否滿足條件
var mutableList = mutableListOf("miku","rin","luka")
val result:Boolean = mutableList.all(){
it.isNotEmpty() //元素的長度大于0
}
none 判斷集合中的所有元素是否都不滿足條件,滿足則回傳true
var mutableList = mutableListOf("miku","rin","luka")
val result:Boolean = mutableList.none(){
it.isNotEmpty() //元素的長度等于0 false
}
count 回傳滿足條件的元素個數,類似sql中的select count(*) from table where xx = xx
var mutableList = mutableListOf("miku","rin","luka")
val result: Int = mutableList.count {
it == "miku" //回傳集合中元素值為miku的元素個數
}
reduce 從第一個元素到最后一個元素的累加
val numbers = mutableListOf(1,2,3,4,5,6,7,8,9)
val result: Int = numbers.reduce() {
sum: Int, i -> sum + i //sum:宣告一個用于接收累加結果的變數 i->:回圈每一個元素,sum + i:累加每個元素到sum
}
reduceRight 從最后一個元素到第一個元素的累加
val numbers = mutableListOf(1,2,3,4,5,6,7,8,9)
val result: Int = numbers.reduceRight() {
sum: Int, i -> sum + i
}
fold 跟reduce類似,不過可以設定初始化,從初始值開始累加
val numbers = mutableListOf(1,2,3,4,5,6,7,8,9)
val result: Int = numbers.fold(10){
sum, i -> sum + i
}
foldRight...
sumOf 回傳集合中所有元素的總和,該集合的元素必須是Number型別
val numbers = mutableListOf(1,2,3,4,5,6,7,8,9)
val result = numbers.sumOf{
it
}
dropWhile 去除滿足條件的元素,直到不滿足為止,回傳剩余元素的集合
val numbers = mutableListOf(1,2,3,4,5,6,7,8,9)
val result = numbers.dropWhile {
it < 5
}
filter 過濾不滿足條件的元素,回傳滿足元素的新集合
val numbers = mutableListOf(1,2,3,4,5,6,7,8,9)
val result = numbers.filter {
it < 5
}
filterNot 過濾滿足條件的元素,回傳不滿足元素的新集合
val numbers = mutableListOf(1,2,3,4,5,6,7,8,9)
val result = numbers.filterNot {
it < 5
}
take 回傳從第一個元素開始的N個元素
val numbers = mutableListOf(1,2,3,4,5,6,7,8,9)
val result = numbers.take(5) //{1,2,3,4,5}
takeLast 回傳從最后一個元素開始的N個元素
...
takeWhile 回傳從第一個元素開始符合給定條件的元素
val numbers = mutableListOf(1,2,3,4,5,6,7,8,9)
val result = numbers.takeWhile {
it > 0
}
drop 回傳去掉N個元素之后的串列
val numbers = mutableListOf(1,2,3,4,5,6,7,8,9)
val result = numbers.drop(1)
dropLastWhile 回傳從最后一個元素開始,去掉滿足條件的元素
val numbers = mutableListOf(1,2,3,4,5,6,7,8,9)
val result = numbers.dropLastWhile {
it > 5
}
slice 保留指定下標對應的元素
val numbers = mutableListOf(1,2,3,4,5,6,7,8,9)
val result = numbers.slice(listOf(1,2,3))
map 將集合中的元素通過某種方法轉換后,回傳一個新集合
val numbers = mutableListOf(1,2,3,4,5,6,7,8,9)
val result = numbers.map {
val diff = 10
it * diff
}
后續更新...
2.6.型別轉換
Kotlin通過as關鍵字將一個型別轉換為另一個型別.
var numberType:Number = 39
var intType:Int = numberType as Int
Kotlin可以通過 is 關鍵字自動完成裝箱的操作.
open class GameConsole{
}
class PS4 : GameConsole() {
}
class NintendoSwitch : GameConsole() {
public val version = "10.0"
}
fun main(args: Array<String>) {
val gameConsoles = arrayOf(PS4(),NintendoSwitch())
val gameConsole = gameConsoles[1]
//會自動完成裝箱操作,在當前呼叫范圍內將gameConsole識別NitendoSwitch,可以直接訪問物件的成員,不需要手動轉換
if(gameConsole is NintendoSwitch){
print(gameConsole.version)
}
}
3.運算子
Kotlin特有的運算子有===、!==
3.1.恒等和非恒等
判斷兩個物件之間的地址是否相等
var obj1 = Object()
var obj2 = Object()
if(obj1 === obj2){
println("恒等")
}
if(obj1 !== obj2){
println("非恒等")
}
3.2.位運算
只有Int和Long型別可以使用.
val i:Int = 10
val j:Int = 20
val result = i shl j //有符號左移
result = i shr j //有符號右移
result = i ushr //無符號右移
result = i and j //按位與
result = i or j //按位或
result = i xor //按位異或
result = i inv j //按位取反
3.3.區間運算子
表示某個值是否在某個范圍或者集合之中.
//i >=0 && i <= 100
if(i in 0..100){
print(i)
}
陣列或者集合是否包含某個值
val names = arrayOf("miku","rin","luka")
if("miku" in names){
print("包含")
}
4.條件陳述句
when是Kotlin提供類似Java中Switch的條件陳述句.它能做到Switch能做到的所有事,并且還提供了更方便的語法.
fun test(i:Int){
when(i){
// case 1
1 ->{
}
//case 2
2 -> {
}
//i >= 3 && i <= 9
in 3..9 ->{
}
//default
else ->{
}
}
}
when如果不提供引數也可以當作if elseif使用
5.回圈陳述句
跟Java的使用差別不大,一般配合區間運算子in來更簡便的使用
val names = arrayOf("miku","rin","luka")
for (name in names){
println(name)
}
//遍歷陣列或集合帶索引
for ((index,name) in names.withIndex()){
}
val i = 0
for (i in 0..99){ //i = 0;i <= 99;i++
println(i)
}
var i = 10
while (i > 0){
println(i)
i--
}
do {
i--
println(i)
}while (i > 0)
//foreach
val numbers = mutableListOf(1,2,3,4,5,6,7,8,9)
numbers.forEach{ it ->
println(it)
}
//foreach 帶索引
val numbers = mutableListOf(1,2,3,4,5,6,7,8,9)
numbers.forEachIndexed{index, i ->
println("index[${index}] = $i")
}
6.函式
Kotlin中定義函式使用fun關鍵字.如果方法不需要回傳值可以不寫,或者寫Unit
fun sum(number1:Int,number2:Int):Int{
return number1 + number2
}
6.1默認引數
Kotlin中添加了默認引數的支持,當一個方法指定了引數的默認值,則呼叫的時候可以不提供該引數的值.
要使用默認引數,在引數的后面添加=進行賦值操作.
fun sum(number1:Int,number2:Int = 0):Int{
return number1 + number2
}
6.2可變引數
和Java一樣,Kotlin也提供可變引數的支持,使用vararg關鍵字宣告可變引數
fun sum(vararg number:Int){
//number在使用的時候其實是一個陣列型別的變數,可以呼叫陣列的一些方法
}
6.3Lambda運算式
Lambda運算式可以看作是一個匿名的函式.
var execute:(Int,Int) -> Int = {x,y ->
x * y
}
println(execute(10,10))
如果函式只有一個引數時可以省略不寫,這個時候用it來表示
var execute:(String) -> String = {
it
}
println(execute("komine"))
6.4高階函式
Kotlin支持將函式作為引數或者回傳值,包含這樣操作的函式稱為高階函式.將函式作為引數時使用雙冒號::來傳遞.
fun main(args: Array<String>) {
call(::method)
}
fun call(m:(number:Int) -> Int){
println(m(39))
}
fun method(number:Int):Int{
return number * number
}
也可以使用Lambda運算式來表示一個匿名引數.
call{number: Int -> return@call number * number }
Kotlin本身也提供了一些高階函式供我們使用,比如apply函式,在Android中初始化變數可以這樣寫.
var paint = Paint().apply {
this.isAntiAlias = true
this.color = Color.BLACK
this.style = Paint.Style.STROKE
this.strokeWidth = 10f
}
6.5行內函式
Kotlin支持行內函式,跟C++的行內函式作用一致,因為函式的執行有壓堆疊和出堆疊的步驟,會帶來一定的開銷.
在將函式宣告為行內函式的時候,在編譯的時候,編譯器會在所有呼叫函式的地方,將函式呼叫直接替換成函式體的內容.
一般來說,行內函式中的嵌套邏輯不能太復雜,C++的行內函式是否替換是由編譯器決定的,Kotlin會按照inline關鍵直接替換.
通過反編譯生成的class檔案可以看到,行內函式就是直接將有函式呼叫的地方,直接替換成函式體的內容.
fun main(args: Array<String>) {
test()
}
inline fun test(){
for (i in 0..99){
println(i)
}
for (i in 0..99){
println(i)
}
for (i in 0..99){
println(i)
}
for (i in 0..99){
println(i)
}
for (i in 0..99){
println(i)
}
for (i in 0..99){
println(i)
}
}
反編譯結果

如果函式的引數中有函式引數型別或者Lambda運算式,也可以使用noinline關鍵字指定不引數行內的函式.
crossinline關鍵字待補充...
二、Kotlin進階
1.協程
協程是跑在執行緒上的產物,它擁有自己的堆疊記憶體和區域變數,被稱為輕量級Thread.它的內部實作是由編譯器來完成的.
官方檔案說明
在使用協程之前,需要添加依賴
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.6.1'
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.6.1'
簡單用法
GlobalScope.launch(context = Dispatchers.Default, start = CoroutineStart.DEFAULT) {
//延時1.5秒
delay(1500L)
println("當前執行緒:" + Thread.currentThread().name)
println("World")
}
println("Hello,")
println("當前執行緒:" + Thread.currentThread().name)
Thread.sleep(3000L)
context:協程的背景關系,這里設定的是CoroutineDispatch協程運行的執行緒調度器,它有四種執行緒模式:
Dispatchers.Default //默認
Dispatchers.IO //作業在其他執行緒
Dispatchers.Main //主執行緒
Dispatchers.Unconfined //不指定就是在當前執行緒,kotlinx.coroutines.DefaultExecutor
也可以自己創建一個協程背景關系,這個背景關系也可以理解為協程所運行在的執行緒.
val context = newSingleThreadContext("single")
start:啟動模式,默認是CoroutineStart.DEFAULT,就是創建之后就會啟動
CoroutineStart.DEFAULT
CoroutineStart.ATOMIC
CoroutineStart.UNDISPATCHED
CoroutineStart.LAZY 懶加載模式,它會回傳一個Job物件,你可以手動開啟它.
val job = GlobalScope.launch(context = Dispatchers.Default, start = CoroutineStart.LAZY) {
//延時1秒
delay(1500L)
println("當前執行緒:" + Thread.currentThread().name)
println("World")
}
println("Hello,")
println("當前執行緒:" + Thread.currentThread().name)
job.start()
Thread.sleep(3000L)
GlobalScope.async 帶回傳值
suspend fun main(args: Array<String>) {
val result = GlobalScope.async {
delay(1000L)
return@async "async"
}
println(result.await())
Thread.sleep(3000)
}
async會阻塞當前協程,會等待當前協程執行完畢,呼叫await()的函式需要使用suspend關鍵字修飾.
協程的掛起,suspend表示當前協程被掛起.
fun main(args: Array<String>) {
GlobalScope.launch {
//get方法是被suspend修飾的,表示呼叫時會將當前協程掛起
val str = get()
//會等待get()執行完畢才會繼續執行
printStr(str)
}
//防止行程結束
Thread.sleep(3000L)
}
suspend fun get():String{
println("get()正在執行..")
delay(1000)
return "data"
}
suspend fun printStr(str:String){
println(str)
}
協程之間也可以嵌套,呼叫await會阻塞外部協程,代碼還是會按順序運行
fun main(args: Array<String>) {
GlobalScope.launch {
val str = GlobalScope.async {
return@async get()
}.await()
GlobalScope.launch{
printStr(str)
}
}
//防止行程結束
Thread.sleep(3000L)
}
suspend fun get():String{
println("get()正在執行..")
delay(1000)
return "data"
}
suspend fun printStr(str:String){
println(str)
}
待補充...
2.面向物件
2.1類的宣告
和很多語言一樣,Kotlin使用class關鍵字來宣告一個類.
class Person{
}
2.1.1內部類
class Person{
//內部類的宣告使用inner關鍵字修飾
inner class Info{
}
}
要實體內部類需要先實體化主類
val person = Person("miku")
val info = person.Info()
2.1.2資料類
通過data class 修飾的類稱為資料類,資料類必須提供一個有參的建構式.資料類一般不定義方法.
data class MyData(val height:Float,val weight:Float,val money:Float){
}
2.1.3列舉類
跟Java的列舉類使用基本相同.
enum class DirectionEnum{
East{
override fun move() {
//name:當前列舉常量的名稱
//ordinal:當前列舉常量的值
println("name$name")
println("value:$ordinal")
}
},
South{
override fun move() {
}
},
West{
override fun move() {
}
},
North{
override fun move() {
}
};
abstract fun move();
}
2.1.4密封類
emm...不知道怎么用,后面補充
2.1.5抽象類
使用abstract關鍵字宣告一個抽象類
open abstract class Person(name:String, age:Int){
}
2.2建構式
Kotlin的建構式可以直接寫在類名的后面,稱為主建構式,這樣定義的建構式是沒有方法體的,要執行初始化操作
可以使用init代碼塊.
open class Person(name:String, age:Int){
init {
println("主建構式執行...")
println("name:${name},age = $age")
}
}
2.2.1 副建構式
通過constructor定義的建構式稱為副建構式,需要間接呼叫主建構式進行初始化
fun main(args: Array<String>) {
val person = Person("miku")
}
open class Person(name:String, age:Int){
init {
println("主建構式執行...")
println("name:${name},age = $age")
}
//副建構式需要間接呼叫主建構式通過this關鍵字
constructor(name:String) : this(name,16) {
println("副建構式執行...")
}
}
2.3繼承
如果想讓一個類可以被其他類繼承,需要在類的宣告之前加上open關鍵字,使用:冒號來繼承
open class Person{
open fun take(){}
}
class Student : Person() {
}
如果子類想重寫父類定義的方法,該方法必須是open關鍵字修飾的方法,抽象方法的修飾符默認是open.
2.4靜態成員
Kotlin沒有提供static關鍵字,如果想實作Java那樣的靜態成員呼叫可以使用companion object代碼塊來定義靜態成員.
在Kotlin中稱為伴生物件,用伴生物件的成員來代替靜態成員.
class PS4{
companion object{
val FIRMWARE_VERSION:Float = 10.0f
fun boot(){
println("boot...")
}
}
}
跟Java一樣,然后通過類名呼叫靜態成員
PS4.boot()
PS4.FIRMWARE_VERSION
2.5介面
使用interface來宣告一個介面.與Java的用法并無二致
interface Callback{
fun onSuccess()
fun onFailed()
}
3.泛型
基本使用和Java一致
class Data<T>(private val data:T){
fun get():T{
return data
}
}
val data1 = Data("String")
println(data1.get())
val data2 = Data(16)
println(data2.get())
3.1out和in關鍵字
Kotlin中使用out和in來代替? extends 和? super使用,具體用法跟Java是類似的.
fun main(){
val ps4List = mutableListOf<PS4>()
setGameConsoles(ps4List)
val gameConsoles = getGameConsoles()
for (gameConsole in gameConsoles){
val ps4 = gameConsole as PS4
ps4.play()
}
}
// out ----> ? extends GamesConsole
fun setGameConsoles(gamConsoles:MutableList<out GameConsole>){
}
//in -----> ? super PS4
fun getGameConsoles():MutableList<in PS4>{
val gameConsoles = mutableListOf<GameConsole>()
gameConsoles.add(PS4())
gameConsoles.add(PS4())
return gameConsoles
}
open class GameConsole{
open fun play(){
}
}
class PS4 : GameConsole(){
override fun play() {
println("ps4 play...")
}
}
class NintendoSwitch : GameConsole(){
override fun play() {
println("ns play...")
}
}
4.委托
其實就是代理設計模式.
4.1委托的使用場景
Java中的代理模式實作
//支付介面
public interface IPay {
void pay();
}
//支付寶支付
public class AliPay implements IPay{
private float mMoney;
public AliPay(float money){
mMoney = money;
}
@Override
public void pay() {
Log.d("Alipay","支付寶支付" + mMoney + "元...");
}
}
//微信支付
public class WeChatPay implements IPay{
private float mMoney;
public WeChatPay(float money){
mMoney = money;
}
@Override
public void pay() {
Log.d("WeChatPay","微信支付" + mMoney + "元...");
}
}
//代理物件
public class ProxyPay implements IPay{
private IPay mPay;
public ProxyPay(IPay pay){
mPay = pay;
}
@Override
public void pay() {
mPay.pay();
}
}
Kotlin的代理模式實作
interface IPay{
fun pay()
}
class Alipay(private val money:Float) :IPay{
override fun pay() {
println("支付寶支付$money...")
}
}
class WeChatPay(private val money: Float) :IPay{
override fun pay() {
println("微信支付$money...")
}
}
class PayDelegate(private val play:IPay) :IPay by play{
//什么都不需要做,系統幫我們完成一系列操作
}
可以看出,Kotlin的委托其實就是簡化了代理模式的實作程序.
4.2屬性委托
將屬性的賦值操作交給其他類來代理.可以通過其他類來統一控制屬性的取值,合法性等等操作.
基本使用
//宣告一個介面,不一定要介面也可以是一個類
interface IPropertyDelegate
class PS4 :IPropertyDelegate{
var version:String by DataDelegate()
}
class NintendoSwitch :IPropertyDelegate{
var version:String by DataDelegate()
}
class DataDelegate {
private var version:String = ""
operator fun setValue(thisRef: IPropertyDelegate, property: KProperty<*>, value: String) {
this.version = value
}
operator fun getValue(thisRef: IPropertyDelegate, property: KProperty<*>): String {
return this.version
}
}
當給PS4或者NintendoSwitch物件的version賦值的時候,就會去到DataDelegate物件的setValue()方法,達到統一賦值的操作,相同的操作不需要在每個類都寫一次
val ps4 = PS4()
ps4.version = "7.55"
println(ps4.version)
val ns = NintendoSwitch()
ns.version = "13.0"
println(ns.version)
5.其他
5.1擴展函式
給某個類添加一個擴展函式,其效果跟成員函式呼叫一致.一般定義到一個統一的檔案中,不需要先定義一個型別,直接寫就好
//給String擴展了一個first方法
fun String.first():Char{
return this[0]
}
println("komine".first())
5.1擴展屬性
給某個類添加一個擴展屬性
val Int.dp:Int
get(){
//簡單模擬一下,開發中不是這么計算的
return this * 1.5f.toInt()
}
比如給Int型別添加了一個dp的擴展屬性,可以將int值轉換為對應的dp
val width = 39.dp
待更新...
轉載請註明出處,本文鏈接:https://www.uj5u.com/yidong/458247.html
標籤:Android
上一篇:【Harmony OS】【ARK UI】ETS 的 List 實作下拉重繪功能實作
下一篇:Kotlin快速上手
