一柱蟀、基礎(chǔ)語(yǔ)法
Kotlin中可變變量、只讀變量蚜厉、靜態(tài)變量长已、常量
格式:修飾符 名稱:類型 = 默認(rèn)值
var num: Int = 10
空安全的聲明方式
var str: String ?= null
可變變量:
var: var是一個(gè)可變變量,這是一個(gè)可以通過(guò)重新分配來(lái)更改為另一個(gè)值的變量昼牛,這種聲明變量的方式和Java中聲明變量的方式一樣术瓮。
特點(diǎn):
可以重寫set和get方法,注意在set和get方法中贰健,變量用field表示胞四,不能用變量本身,否則會(huì)出現(xiàn)循環(huán)調(diào)用伶椿。
var num2 = 10
set(value) {
field = value + 5
}
get() {
return field + 5
}
只讀變量:
val: val是一個(gè)只讀變量辜伟,這種聲明變量的方式相當(dāng)于java中的final變量,一個(gè)val創(chuàng)建的時(shí)候必須初始化脊另,因?yàn)橐院蟛荒鼙桓淖儭?/p>
特點(diǎn):
只能重寫get方法导狡,不能重寫set方法
val num3 = 10
get() {
return field + 5
}
靜態(tài)變量:
Kotlin中聲明靜態(tài)變量的方法是將對(duì)象放在對(duì)象中聲明。
/**
* 靜態(tài)類
*/
object StaticData {
/**
* 靜態(tài)變量(private)
*/
var num6 = 10
}
如果把變量放到一個(gè)普通對(duì)象中偎痛,聲明出來(lái)的變量是私有的旱捧,外部調(diào)用不到,推薦使用伴生對(duì)象來(lái)聲明靜態(tài)變量踩麦。
/**
* 伴生對(duì)象
*/
companion object {
/**
* 靜態(tài)變量
*/
var num4 = 10
}
伴生對(duì)象相當(dāng)于是外部類的對(duì)象枚赡,我們可以使用類直接調(diào)用,在伴生對(duì)象中聲明的變量谓谦,實(shí)際上編譯成java代碼后對(duì)象都聲明在了伴生對(duì)象的外部類里面了贫橙,伴生對(duì)象里面只是生成的set和get方法。
常量:
常量值是在編譯時(shí)期就確定下來(lái)的反粥,因此常量值可以直接賦值料皇,也可以賦值為其他常量值,但不能賦值為非常量值星压,即不可以用沒(méi)有被const修飾的變量給它賦值践剂,
const只能修飾val,不能修飾var娜膘。
const val 常量值的名字 = 常量值
聲明一個(gè)常量可以在伴生對(duì)象中聲明
object StaticData {
/**
* 常量:const val
*/
const val num7 = 10
}
也可以在類外面聲明逊脯,用這種方法聲明的常量,相當(dāng)與創(chuàng)建了一個(gè) 類名稱 + Kt(KotlinTestActivitykt)的對(duì)象竣贪,常量屬于這個(gè)對(duì)象
const val num8 = 10
open class KotlinTestActivity : BaseActivity(), View.OnClickListener
二军洼、Kotlin中的方法
Kotlin中聲明方法的格式:
fun [方法名] ( [參數(shù)名] : [參數(shù)類型] ) : [返回類型]{
...
return [返回值]
}
有返回值:
fun add(num1: Int, num2: Int): Int {
return num1 + num2
}
無(wú)返回值巩螃,Unit代表為空,可以省略:
fun log(msg: String): Unit {
print(msg)
}
fun log(msg: String) {
print(msg)
}
靜態(tài)方法:需要聲明在對(duì)象中object
/**
* 伴生對(duì)象
*/
companion object {
/**
* 靜態(tài)方法
*/
fun getData(): Int {
return 1
}
/**
* 靜態(tài)方法
*/
@JvmStatic
fun getNewData(): Int {
return 2
}
}
在Java中調(diào)用需要加companion
KotlinTestActivity.Companion.getNum4()
可以通過(guò)注解@JvmStatic省略Companion直接調(diào)用
KotlinTestActivity.getNewData()
Kotlin中的方法重載:
Java中不同參數(shù)匕争,類型的方法重寫需要寫多個(gè)方法唬涧,在Kotlin中只需要聲明一個(gè)方法就可以解決号涯。
/**
* @param arg1 必傳
* @param arg2 必傳
* @param arg3 必傳
* @param arg4 可不傳,不傳時(shí)默認(rèn)值 2
* @param arg5 可不傳,不傳時(shí)默認(rèn)值 test
*/
fun test(arg1: String?, arg2: Int?, arg3: String?, arg4: Int? = 2, arg5: String? = "test") {
}
方法中的參數(shù)可以設(shè)置默認(rèn)值晚树,在外部沒(méi)有傳值得情況就可以用默認(rèn)值來(lái)代替寓涨,上面那個(gè)方法中后兩個(gè)參數(shù)有默認(rèn)值嚷那,所有在調(diào)用這個(gè)方法的時(shí)候是可以不傳那兩個(gè)參數(shù)的啡彬,如果參數(shù)沒(méi)有默認(rèn)值,是必傳的德谅。
test("arg1", 2, "arg3", 4, "arg5")
test("arg1", 2, "arg3")
Kotlin方法中的參數(shù)也可以不一設(shè)定的順序傳遞爹橱,需要指定傳遞的哪個(gè)參數(shù)
test(arg1 = "arg1", arg2 = 2, arg3 = "arg3")
test(arg3 = "arg3", arg1 = "arg1", arg2 = 2)
三、Kotlin中的null安全
Kotlin將變量分為可以為Nullable類型和Non-Null類型窄做,變量默認(rèn)Non-Null類型愧驱,如果想聲明Nullable的變量,需要用“?”修飾椭盏,
加?表示該變量可能為空,不加則表示一定不會(huì)指向一個(gè)空引用冯键。
聲明Nullable類型變量
var name: String? = null
聲明Non-Null類型變量
var name1: String = ""
name1可以直接賦值給name
name = name1
但是name要賦值給name1,必須加S购埂惫确!
name1 = name!!
如果name為空,就會(huì)拋出KotlinNullPointerException異常蚯舱,所以Nullable類型變量要賦值給Non-Null類型變量時(shí)改化,要先判斷是否為空,不為空才可以賦值枉昏,并且不建議使用3赂亍!兄裂。
四句旱、Kotlin中的 data class
在 Kotlin 中,不需要自己動(dòng)手去寫一個(gè) JavaBean晰奖,可以直接使用 DataClass谈撒,使用 DataClass 編譯器會(huì)默默地幫我們生成以下方法
set()
get()
equals()
hashCode()
toString()
componentN()
copy()
定義一個(gè) data class 類:
data class UserData(
var name: String,
var age: Int = 20,
var avatar: String? = null,
var userInfo: UserInfo? = null
)
雖然data class為我們生成了很多方法,減少了我們的很多代碼量匾南,但是data class 存在兩個(gè)問(wèn)題啃匿,沒(méi)有無(wú)參數(shù)的構(gòu)造方法,而且是被final修飾不能被繼承,不過(guò)可以利用官方給出的插件來(lái)解決這些問(wèn)題(noarg溯乒、allopen)夹厌。
buildscript {
dependencies {
classpath "org.jetbrains.[kotlin:kotlin-noarg:$kotlin_version](http://kotlinkotlin-noarg%24kotlin_version/)"
classpath "org.jetbrains.[kotlin:kotlin-allopen:$kotlin_version](http://kotlinkotlin-allopen%24kotlin_version/)"
}
}
通過(guò)插件可以幫我們?nèi)サ鬰lass的final關(guān)鍵字,并且生成一個(gè)無(wú)參的構(gòu)造方法裆悄,但是由于是在編譯器做的操作矛纹,所以在源代碼中還是無(wú)法直接使用無(wú)參的構(gòu)造函數(shù),只能通過(guò)反射來(lái)使用光稼。
@KotlinData
data class OneData(var arg: String)
class NewData(var arg2: String, var arg3: Int, arg: String): OneData(arg)
如果需要無(wú)參的構(gòu)造方法或南,可以給每個(gè)變量都設(shè)置初始默認(rèn),或者采用一般的class
data class UserInfo(
var info1: String? = null,
var info2: String? = null,
var info3: Int = 0
)
一般的class
class OtherInfo {
var info1: String? = null
var info2: String? = null
var info3: Int = 0
}
五钟哥、Kotlin中擴(kuò)展函數(shù)
擴(kuò)展函數(shù)實(shí)際上就是一個(gè)對(duì)應(yīng)Java中的靜態(tài)函數(shù),這個(gè)靜態(tài)函數(shù)參數(shù)為接收者類型的對(duì)象瞎访,然后利用這個(gè)對(duì)象就可以訪問(wèn)這個(gè)類中的成員屬性和方法了腻贰,并且最后返回一個(gè)這個(gè)接收者類型對(duì)象本身。這樣在外部感覺(jué)和使用類的成員函數(shù)是一樣的扒秸,它并沒(méi)有改變類本身播演。
擴(kuò)展函數(shù)的使用:
只需要把擴(kuò)展的類或者接口名稱,放到即將要添加的函數(shù)名前面伴奥。這個(gè)類或者名稱就叫做接收者類型写烤,類的名稱與函數(shù)之間用"."調(diào)用連接。this指代的就是接收者對(duì)象拾徙,它可以訪問(wèn)擴(kuò)展的這個(gè)類可訪問(wèn)的方法和屬性洲炊。
fun test(str: String): String {
return "back$str"
}
fun TextView.setColor(colorRes: Int) {
this.setTextColor(context.getColor(colorRes))
}
fun ImageView.loadImage(drawableRes: Int) {
Glide.with(this)
.load(drawableRes)
.into(this)
}
在外面調(diào)用:
var test = getBack("test")
tv_age?.setColor(R.color.color_4)
tv_avatar?.loadImage(R.drawable.head_bg_img)
Kotlin擴(kuò)展函數(shù)允許我們?cè)诓桓淖円延蓄惖那闆r下,為類添加新的函數(shù)尼啡,在java要調(diào)用擴(kuò)展函數(shù)要將被擴(kuò)展的對(duì)象傳進(jìn)去暂衡。
KotlinExtensionKt.getBack("test");
KotlinExtensionKt.setColor(tv, R.color.color_0);
KotlinExtensionKt.loadImage(iv, R.drawable.head_bg_img);
六、Kotlin中的Lambda表達(dá)式和高階函數(shù)
1崖瞭、Lambda表達(dá)式的本質(zhì)其實(shí)是匿名函數(shù)狂巢,因?yàn)樵谄涞讓訉?shí)現(xiàn)中還是通過(guò)匿名函數(shù)來(lái)實(shí)現(xiàn)的。
2书聚、將函數(shù)作為另一個(gè)函數(shù)的參數(shù)或者返回值的函數(shù)是高階函數(shù)
語(yǔ)法:
1\. 無(wú)參數(shù)的情況 :
val/var 變量名 = { 操作的代碼 }
2\. 有參數(shù)的情況
val/var 變量名 : (參數(shù)的類型唧领,參數(shù)類型,...) -> 返回值類型 = {參數(shù)1雌续,參數(shù)2斩个,... -> 操作參數(shù)的代碼 }
可等價(jià)于
// 此種寫法:即表達(dá)式的返回值類型會(huì)根據(jù)操作的代碼自推導(dǎo)出來(lái)。
val/var 變量名 = { 參數(shù)1 : 類型驯杜,參數(shù)2 : 類型, ... -> 操作參數(shù)的代碼 }
3\. lambda表達(dá)式作為函數(shù)中的參數(shù)的時(shí)候萨驶,這里舉一個(gè)例子:
fun test(a : Int, 參數(shù)名 : (參數(shù)1 : 類型,參數(shù)2 : 類型, ... ) -> 表達(dá)式返回類型){
...
}
特點(diǎn):
1艇肴、Lambda表達(dá)式總是被大括號(hào)括著
2腔呜、其參數(shù)(如果存在)在 -> 之前聲明(參數(shù)類型可以省略)
3叁温、函數(shù)體(如果存在)在 -> 后面。
舉例:
1核畴、無(wú)參數(shù)的情況
// 源代碼
fun test() {
println("無(wú)參數(shù)")
}
// lambda代碼
val test = {
println("無(wú)參數(shù)")
}
// 調(diào)用
test() => 結(jié)果為:無(wú)參數(shù)
2膝但、有參數(shù)的情況
// 源代碼
fun test(a : Int , b : Int) : Int{
return a + b
}
// lambda
val test : (Int , Int) -> Int = {a , b ->
a + b
}
// 或者
val test = {a : Int , b : Int ->
a + b
}
// 調(diào)用
test(3,5) => 結(jié)果為:8
3、Lambda表達(dá)式作為函數(shù)中的參數(shù)的時(shí)候
// 源代碼
fun test(a : Int , b : Int) : Int{
return a + b
}
fun sum(num1 : Int , num2 : Int) : Int{
return num1 + num2
}
// 調(diào)用
test(10,sum(3,5))
// 結(jié)果為:18
// lambda
fun test(a : Int , b : (num1 : Int , num2 : Int) -> Int) : Int{
return a + b.invoke(3,5)
}
// 調(diào)用
test(10,{ num1: Int, num2: Int ->
num1 + num2
})
// 結(jié)果為:18
七谤草、Kotlin的使用
1跟束、創(chuàng)建一個(gè)Activity默認(rèn)是私有的,如果這個(gè)activity可以被繼承需要加open修飾
2丑孩、Java中的繼承 extends 和實(shí)現(xiàn) implements 在Kotlin中都可以用 :替換冀宴,多個(gè)implements之間添加 ,
open class KotlinTestActivity : BaseActivity(), View.OnClickListener
3、在布局中的View可以在activity直接調(diào)用温学,Kotlin默認(rèn)給實(shí)現(xiàn)findViewById
<TextView
android:id="@+id/tv_age"
android:layout_width="100dp"
android:layout_height="40dp"
android:layout_margin="20dp"/>
tv_age?.setColor(R.color.color_4)
查看Kotlin轉(zhuǎn)換成java后的代碼
public View _$_findCachedViewById(int var1) {
if (this._$_findViewCache == null) {
this._$_findViewCache = new HashMap();
}
View var2 = (View)this._$_findViewCache.get(var1);
if (var2 == null) {
var2 = this.findViewById(var1);
this._$_findViewCache.put(var1, var2);
}
return var2;
}
var10000 = (TextView)this._$_findCachedViewById(id.tv_age);
if (var10000 != null) {
KotlinExtensionKt.setColor(var10000, 500082);
}
4略贮、Kotlin中的多個(gè)數(shù)據(jù)可以拼接成一個(gè)String用{} 包起來(lái)
var num: Int = 10
var user1 = UserData("name1”)
println("num = $num")
println("num = ${user1.age}")
5仗岖、設(shè)置監(jiān)聽(tīng)事件
系統(tǒng)的OnClickListener, OnTouchListener等屬于SAM 構(gòu)造可以使用Lambda替換逃延,具體分析:
https://blog.csdn.net/blovecat/article/details/103767059
tv_avatar?.setOnClickListener(object : View.OnClickListener {
override fun onClick(v: View?) {
}
})
// 當(dāng)lambda表達(dá)式是函數(shù)調(diào)用的最后一個(gè)實(shí)參,它可以放到括號(hào)的外邊轧拄。
tv_avatar?.setOnClickListener() {
}
// 當(dāng)lambda表達(dá)式是函數(shù)唯一實(shí)參時(shí)揽祥,還可以去掉代碼中的空括號(hào)對(duì)
tv_avatar?.setOnClickListener {
}
// 當(dāng)lambda表達(dá)式只有一個(gè)參數(shù),那么在調(diào)用該lambda表達(dá)式時(shí),可以不指定它的參數(shù)名字,在lambda函數(shù)體內(nèi)用it來(lái)代表這個(gè)參數(shù).
tv_avatar?.setOnClickListener {
it.alpha = 1f
}
// 當(dāng)lambda表達(dá)式有多個(gè)參數(shù),那么在調(diào)用該lambda表達(dá)式時(shí),必須指定每一個(gè)參數(shù)的名字,如果某個(gè)參數(shù)用不到可以用 _ 來(lái)代替
tv_avatar?.setOnTouchListener { _, event ->
if (event.action == MotionEvent.ACTION_DOWN) {
}
false
}
5、自定義View 三個(gè)構(gòu)造方法可以寫成一個(gè)
Java自定義View
public class TestView extends View {
public TestView(Context context) {
this(context,null);
}
public TestView(Context context, AttributeSet attrs) {
this(context, attrs,0);
}
public TestView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
}
6檩电、Kotlin自定義View
class TestView @JvmOverloads constructor(context: Context?, attrs: AttributeSet? = null, defStyleAttr: Int = 0)
: View(context, attrs, defStyleAttr) {
// 定義接口回調(diào)方式
var testListener: TestListener? = null
// Lambda 表達(dá)式回調(diào)
var callBack = { s: String, i: Int -> Unit}
// Lambda 表達(dá)式回調(diào)簡(jiǎn)化
var callBack2: ((String) -> Unit)? = null
var callBack3: ((String, Int) -> Unit)? = null
/**
* 系統(tǒng)的初始化方法
*/
init {
}
fun backData() {
callBack.invoke("back", 0)
}
fun backData2() {
callBack2?.invoke("back")
callBack3?.invoke("back", 1)
}
fun setCallBack(listener: TestListener?) {
this.testListener = listener
}
}
Kotlin接口定義:
interface TestListener {
fun callBack1()
/**
* 在java中拄丰,接口中定義的方法不可以實(shí)現(xiàn),實(shí)現(xiàn)類必須實(shí)現(xiàn)所有方法
* 在Kotlin中俐末,接口中的方法可提前進(jìn)行空實(shí)現(xiàn)愈案,實(shí)現(xiàn)類可不實(shí)現(xiàn)其不用的方法
*/
fun callBack2() {}
}
Activit中調(diào)用回調(diào)函數(shù):
var view = TestView(this)
view.setCallBack(object: TestListener{
override fun callBack1() {
}
})
view.callBack = { _: String, _: Int ->
}
view.callBack2 = {
}
7、單例模式
/**
* @Author: zs
* @Date: 20/12/23 上午8:29
* @Description:
*/
class InstanceKotlin {
companion object{
@Volatile
private var mUtil: InstanceKotlin? = null
/**
* 兩次判空實(shí)現(xiàn)單例
* @return
*/
val instance1: InstanceKotlin?
get() {
if (mUtil == null) {
synchronized(InstanceKotlin::class.java) {
if (mUtil == null) {
mUtil = InstanceKotlin()
}
}
}
return mUtil
}
/**
* 靜態(tài)內(nèi)部類實(shí)現(xiàn)單例
* @return
*/
val instance2: InstanceKotlin
get() = TestHolder.instance
private object TestHolder {
val instance: InstanceKotlin = InstanceKotlin()
}
}
}