次級構造
申明前綴有construct修飾
class Person {
constructor(parent: Person){
}
}
如果有一個主構造函數(shù),每個次構造函數(shù)需要委托給主構造函數(shù),可以直接委托或者通過別的構造函數(shù)
class constructor Person(val name:String) {
constructor(name: String,parent: Person):this(name){
}
}
主構造器
主構造函數(shù):是類頭的一部分,跟在類名后面(可帶參數(shù)),沒有任何注解和可見性修飾符。如:
class User (username : String?,password : String?) {
}
主構造函數(shù)中沒有任何代碼,初始化代碼放在關鍵字init的代碼塊中;也可以在類體內聲明的屬性初始化器中使用
class User (username : String?,password : String?) {
init {
//執(zhí)行你的操作
}
}
class User (username : String?) {}
var username=username.getname()
}
init 代碼塊
主構造不能包含任何的代碼,初始化代碼可以放到 init 代碼塊中
class CodeView constructor(context: Context) :
TextView(context) {
init {
//...
}
}
在初始化的時候,初始化塊會按照它們在 文件中出現(xiàn)的順序 執(zhí)行
Kotlin 中的初始化塊會按照它們在文件中出現(xiàn)的順序執(zhí)行??梢栽谄渲袌?zhí)行一些特定的初始化操作。
例如,以下是一個包含兩個初始化塊的 Kotlin 類示例:
class MyClass {
var myProperty1: String? = null
init {
println("Initializing myProperty1")
myProperty1 = "Hello"
}
init {
println("Initializing myProperty2")
// 在這里可以進行其他初始化操作
}
}
在上面的示例中,MyClass 類包含兩個初始化塊。第一個初始化塊初始化了 myProperty1 屬性,并將其設置為 “Hello”。第二個初始化塊只是打印一條消息,并沒有對任何屬性進行初始化。由于初始化塊按照它們在文件中出現(xiàn)的順序執(zhí)行,因此第一個初始化塊會先執(zhí)行,然后是第二個初始化塊。
當創(chuàng)建 MyClass 的實例時,輸出將是以下內容:
Initializing myProperty1
Initializing myProperty2
這表明第一個初始化塊先執(zhí)行,然后是第二個初始化塊。
構造屬性
在 Kotlin 中,構造屬性是一種特殊的屬性,它在類實例化時通過構造器進行初始化。構造屬性可以通過在主構造器參數(shù)前面加上 var/val 關鍵字來定義,使其同時成為成員變量。
下面是一個使用構造屬性的示例:
class Person(var name: String, var age: Int) {
init {
println("Person instance is created with name: $name and age: $age")
}
}
fun main() {
val person = Person("John Doe", 30)
println(person.name) // 輸出: John Doe
println(person.age) // 輸出: 30
}
在上面的示例中,Person 類有兩個構造屬性 name 和 age,它們在類的構造函數(shù)中聲明,并使用 var 關鍵字進行定義,使其同時成為成員變量。在 init 塊中,我們可以訪問這些屬性并執(zhí)行初始化操作。在 main 函數(shù)中,我們創(chuàng)建了一個 Person 實例,并訪問了其屬性。
data class
數(shù)據(jù)類中自動生成
-
toString()
-
hashCode()
-
equals()
-
copy() (淺拷?)
-
componentN()
使用數(shù)據(jù)類的好處包括:簡化代碼、減少錯誤
相等性
-
== 結構相等 (調用 equals() 比較 )
-
=== 引用(地址值)相等
解構
可以把一個對象「解構」成很多變量
val (username,password) = User
對應的Java代碼
val username = User.component1()
val password = User.component2()
Elvis 操作符
可以通過 ?: 的操作來簡化 if null 的操作
// lesson.date 為空時使用默認值
val date = lesson.date?: "日日期待定"
// lesson.state 為空時提前返回函數(shù)
val state = lesson.state?: return
// lesson.content 為空時拋出異常
val content = lesson.content ?: throw IllegalArgumentException("content expected")
when 操作符
when 表達式可以接受返回值,多個分支相同的處理方式可以放在一起,用逗號分隔
val colorRes = when (lesson.state) {
Lesson.State.PLAYBACK, null -> R.color.playback
Lesson.State.LIVE -> R.color.live
Lesson.State.WAIT -> R.color.wait
}
when 表達式可以用來取代 if-ese-if
鏈。如果不提供參數(shù),所有的分支條件都是布爾表達式
val colorRes = when {
(lesson.state == Lesson.State.PLAYBACK) ->
R.color.playback
(lesson.state == null) -> R.color.playback
(lesson.state == Lesson.State.LIVE) -> R.color.live
(lesson.state == Lesson.State.WAIT) -> R.color.wait
else -> R.color.playback
}
operator
通過 operator
修飾「特定函數(shù)名」的函數(shù),例如 plus
、 get
,可以達到重載運算符的效果
表達式 | 翻譯為 |
---|---|
a + b | a.plus(b) |
a - b | a.minus(b) |
a * b | a.times(b) |
a / b | a.div(b) |
fun main() {
val num1 = ComplexNumber(2.0, 3.0)
val num2 = ComplexNumber(4.0, 5.0)
val result1 = num1 + num2 // 使用重載的加法運算符
val result2 = num1 - num2 // 使用重載的減法運算符
val result3 = num1 * num2 // 使用重載的乘法運算符
val result4 = num1 / num2 // 使用重載的除法運算符
println("Result 1: $result1")
println("Result 2: $result2")
println("Result 3: $result3")
println("Result 4: $result4")
Lambda
Lambda 表達式被廣泛使用,它們使得編寫簡潔、優(yōu)雅的代碼更加容易
如果函數(shù)的最后一個參數(shù)是 lambda ,那么 lambda 表達式可以放在圓括號之外:
lessons.forEach(){ lesson : Lesson ->
// ...
}
如果你的函數(shù)傳入?yún)?shù)只有一個 lambda 的話,那么小括號可以省略的:
lessons.forEach { lesson : Lesson ->
// ...
}
如果 lambda
表達式只有一個參數(shù),那么可以省略,通過隱式的 it
來訪問
lessons.forEach { // it
// ...
}
循環(huán)
通過標準函數(shù) repeat() :
repeat(100) {
println(it)
}
通過區(qū)間
for (i in 0..99) {
}
// until 不包括右邊界
for (i in 0 until 100) {
}
infix 函數(shù)
必須是成員函數(shù)或擴展函數(shù)
必須只能接受一個參數(shù),并且不能有默認值
// until() 函數(shù)的源碼
public infix fun Int.until(to: Int): IntRange {
if (to <= Int.MIN_VALUE) return IntRange.EMPTY
return this .. (to - 1).toInt()
}
Kotlin 的 infix 函數(shù)是一種特殊的函數(shù),其名稱即為所表達的操作,可以簡化代碼。它們通常用于簡化對兩個對象之間的操作。
下面是一個簡單的 infix 函數(shù)示例:
infix fun Int.add(other: Int): Int {
return this + other
}
這個函數(shù)將兩個整數(shù)相加,返回它們的和。通過使用 infix 關鍵字,我們可以在不創(chuàng)建新的函數(shù)對象的情況下直接在兩個整數(shù)之間調用這個函數(shù)。例如:
val result = 2 + 3 // 這里使用了 infix 函數(shù)
println(result) // 輸出:5
在這個例子中,我們直接在 2 和 3 之間調用了 add 函數(shù),而不是像普通函數(shù)那樣需要使用函數(shù)名稱和括號。
需要注意的是,infix 函數(shù)只能有一個參數(shù),而且必須是函數(shù)的最后一個參數(shù)。此外,infix 函數(shù)不能改變函數(shù)參數(shù)的值,因為它們被視為只讀的。
嵌套函數(shù)
Kotlin 中可以在函數(shù)中繼續(xù)聲明函數(shù)
fun main() {
// 外部函數(shù)
fun outerFunction() {
// 內部函數(shù)
fun innerFunction() {
println("我是內部函數(shù)")
}
innerFunction() // 調用內部函數(shù)
}
outerFunction() // 調用外部函數(shù)
}
在這個示例中,innerFunction 是 outerFunction 的嵌套函數(shù)。我們首先調用了 outerFunction,然后在 outerFunction 的內部調用了 innerFunction,嵌套函數(shù)對于封裝和代碼組織非常有用,可以在一個函數(shù)內部定義一些輔助函數(shù)或私有方法
- 內部函數(shù)可以訪問外部函數(shù)的參數(shù)
- 每次調用時,會產生一個函數(shù)對象
注解使用處目標
注解(Annotation)被用作一種元數(shù)據(jù)機制,用于向編譯器傳遞額外的信息,或者用于在運行時進行反射
當某個元素可能會包含多種內容(例如構造屬性,成員屬性),使用注解時可以通過「注解使用處目標」,讓注解對目標發(fā)生作用,例如 @file: 、 @get: 、@set: 等。
- @file:jvmName 指定生成的 Java 字節(jié)碼文件中該函數(shù)的 JVM 名稱
- @get:jvmName注解的作用是用于指定生成的Java字節(jié)碼文件中該屬性的JVM名稱
- @set:jvmName 注解的作用是用于指定生成的 Java 字節(jié)碼文件中該屬性的 JVM 名稱
函數(shù)簡化
可以通過符號 = 簡化原本直接 return 的函數(shù)
函數(shù)參數(shù)默認值
Kotlin 中使用函數(shù)參數(shù)默認值的示例:
fun printMessage(message: String = "Hello") {
println(message)
}
printMessage() // 輸出 "Hello"
printMessage("World") // 輸出 "World"
可以通過函數(shù)參數(shù)默認值來代替 Java 的函數(shù)重載
// 使用 @JvmOverloads 對 Java 暴露重載函數(shù)
@JvmOverloads
fun toast(text: CharSequence, duration: Int =
Toast.LENGTH_SHORT) {
Toast.makeText(this, text, duration).show()
}
在Java中,重載函數(shù)(也稱為方法)是指在一個類中定義多個具有相同名稱但參數(shù)列表不同的方法。這些方法通常具有不同的行為,以處理不同的輸入?yún)?shù),通過使用相同的方法名,Java允許您根據(jù)傳遞給方法的參數(shù)類型和數(shù)量來調用適當?shù)姆椒ā?/p>
public class Example {
public void print(String message) {
System.out.println(message);
}
public void print(int number) {
System.out.println(number);
}
}
在上面的示例中,print 方法被重載了兩次,一次接受一個字符串參數(shù),另一次接受一個整數(shù)參數(shù)。根據(jù)調用時傳遞的參數(shù)類型,將調用適當?shù)姆椒?/p>
擴展
-
擴展函數(shù)可以為任何類添加上一個函數(shù),從而代替工具類
-
擴展函數(shù)和成員函數(shù)相同時,成員函數(shù)優(yōu)先被調用
-
擴展函數(shù)是靜態(tài)解析的,在編譯時就確定了調用函數(shù)(沒有多態(tài))
函數(shù)類型
函數(shù)類型由「傳入?yún)?shù)類型」和「返回值類型」組成,用「 -> 」連接,傳入?yún)?shù)需要用「 () 」,如果返回值為 Unit 不能省略 函數(shù)類型實際是一個接口,我們傳遞函數(shù)的時候可以通過「 ::函數(shù)名 」,或者「匿名函數(shù)」或者使用 「 lambda 」
匿名函數(shù)
lambda
Java中調用
傳遞函數(shù)
內聯(lián)函數(shù)
內聯(lián)函數(shù) 的語義很簡單:把函數(shù)體復制粘貼到函數(shù)調用處 。使用起來也毫無困難,用 inline關鍵字修飾函數(shù)即可。
用inline修飾的函數(shù)就是內聯(lián)函數(shù),inline修飾符影響函數(shù)本身和傳給它的lambda表達式,所有這些都將內聯(lián)到調用處,即編譯器會把調用這個函數(shù)的地方,用這個函數(shù)的方法體進行替換,而不是創(chuàng)建一個函數(shù)對象并生成一個引用
內聯(lián)函數(shù)配合「函數(shù)類型」,可以減少「函數(shù)類型」生成的對象
使用 inline
關鍵字聲明的函數(shù)是「內聯(lián)函數(shù)」,在「編譯時」會將「內聯(lián)函數(shù)」中的函數(shù)體直接插入到調用處。
所以在寫內聯(lián)函數(shù)的時候需要注意,盡量將內聯(lián)函數(shù)中的代碼行數(shù)減少!
Kotlin內聯(lián)函數(shù)的使用是通過關鍵字inline來聲明的。內聯(lián)函數(shù)在編譯時會被插入到調用它的代碼位置,以減少函數(shù)調用的開銷。
下面是一個簡單的Kotlin內聯(lián)函數(shù)的示例:
inline fun max(a: Int, b: Int): Int {
return a > b ? a : b
}
在這個例子中,max函數(shù)被聲明為內聯(lián)函數(shù)。當你在代碼中調用max函數(shù)時,Kotlin編譯器會將其代碼直接插入到調用處,而不是進行常規(guī)的函數(shù)調用。
需要注意的是,內聯(lián)函數(shù)的參數(shù)必須是具體的類型,不能是可空類型。此外,內聯(lián)函數(shù)的代碼必須非常簡單,否則會增加代碼的大小和編譯的時間。
除了在函數(shù)定義時使用inline關鍵字,還可以在調用函數(shù)時使用inline關鍵字來強制內聯(lián)函數(shù)。例如:
fun main(args: Array<String>) {
inline fun printMax(a: Int, b: Int) {
println(max(a, b))
}
printMax(10, 20) // 內聯(lián)函數(shù)調用
printMax(100, 200) // 內聯(lián)函數(shù)調用
}
在這個例子中,printMax函數(shù)被聲明為內聯(lián)函數(shù),并在調用時使用了inline關鍵字。這樣,Kotlin編譯器會將其代碼直接插入到調用處,而不是進行常規(guī)的函數(shù)調用。
部分禁用用內聯(lián)
noinline
可以禁止部分參數(shù)參與內聯(lián)編譯
inline fun foo(inlined: () -> Unit, noinline notInlined:
() -> Unit) {
//......
}
在Kotlin中,內聯(lián)函數(shù)是默認情況下會被編譯器內聯(lián)的函數(shù)。內聯(lián)函數(shù)的優(yōu)點是可以減少函數(shù)調用的開銷,提高代碼的執(zhí)行效率。但是,如果內聯(lián)函數(shù)的代碼較大,會增加代碼的大小,從而影響到程序的整體性能。
noinline關鍵字可以用于禁止某些特定參數(shù)參與內聯(lián)編譯。當你在定義一個函數(shù)時,可以使用noinline關鍵字來標記某些參數(shù),這樣編譯器就不會將這些參數(shù)內聯(lián)到調用該函數(shù)的地方。
下面是一個使用noinline關鍵字的示例:
fun foo(inlineParam: Int, noinlineParam: String) {
// 函數(shù)內容
}
在這個例子中,inlineParam參數(shù)會被編譯器內聯(lián),而noinlineParam參數(shù)則不會被內聯(lián)。這樣,當你在調用foo函數(shù)時,編譯器會將inlineParam參數(shù)直接插入到調用處,而noinlineParam參數(shù)則保持原樣,不會參與內聯(lián)編譯。
需要注意的是,使用noinline關鍵字會使得代碼的大小增加,因為編譯器需要保留每個函數(shù)的獨立代碼塊。因此,在使用noinline關鍵字時需要權衡代碼大小和執(zhí)行效率之間的利弊。
具體化的類型參數(shù)
因為內聯(lián)函數(shù)的存在,我們可以通過配合 inline + reified
達到「真泛型」的效果
val RETROFIT = Retrofit.Builder()
.baseUrl("https://api.hencoder.com/")
.build()
inline fun <reified T> create(): T {
return RETROFIT.create(T::class.java)
}
val api = create<API>()
在Kotlin中,內聯(lián)函數(shù)(inline function)和具體化的類型參數(shù)(reified type parameter)結合使用可以實現(xiàn)類似于“真泛型”的效果。
內聯(lián)函數(shù)是指在函數(shù)定義中直接將函數(shù)體插入到調用處,從而減少函數(shù)調用的開銷。內聯(lián)函數(shù)的優(yōu)點是可以提高代碼的執(zhí)行效率,但需要注意的是,內聯(lián)函數(shù)的代碼行數(shù)不宜過多,否則可能會增加代碼的長度和編譯時間。
具體化的類型參數(shù)是指在進行泛型編程時,將類型參數(shù)具體化為實際的類型。在Kotlin中,使用reified修飾符可以將泛型類型參數(shù)具體化,這樣就可以在運行時獲取泛型類型的實際類型信息。
通過配合內聯(lián)函數(shù)和具體化的類型參數(shù),可以實現(xiàn)類似于“真泛型”的效果。在Kotlin中,可以使用內聯(lián)函數(shù)和reified類型參數(shù)來實現(xiàn)類似于Java中的靜態(tài)類型檢查和運行時類型信息獲取。
下面是一個簡單的示例代碼:
inline fun <reified T> printInstance(instance: T) {
val className = T::class.java.simpleName
println("The instance of $className is: $instance")
}
fun main() {
val stringInstance = "Hello, world!"
val intInstance = 42
printInstance(stringInstance) // 輸出:The instance of String is: Hello, world!
printInstance(intInstance) // 輸出:The instance of Int is: 42
}
在這個示例中,我們定義了一個內聯(lián)函數(shù)printInstance,它接受一個類型為T的參數(shù)instance。通過使用reified修飾符,我們可以在運行時獲取泛型類型的實際類型信息。在函數(shù)內部,我們使用T::class.java.simpleName來獲取泛型類型的名稱,并使用println打印出實例的值和類型信息。
在main函數(shù)中,我們分別傳遞了一個字符串實例和一個整數(shù)實例給printInstance函數(shù)。由于使用了內聯(lián)函數(shù)和具體化的類型參數(shù),我們可以直接在函數(shù)內部獲取泛型類型的實際類型信息,并打印出實例的值和類型信息。
抽象屬性
在 Kotlin 中,我們可以聲明抽象屬性,子類對抽象屬性重寫的時候需要重寫對應的setter/getter
委托
屬性委托
有些常?的屬性操作,我們可以通過委托的方式,讓它只實現(xiàn)一次,例如:lazy
延遲屬性:值只在第一次訪問的時候計算observable
可觀察屬性:屬性發(fā)生改變時的通知map
集合:將屬性存在一個 map 中
對于一個只讀屬性(即 val 聲明的),委托對象必須提供一個名為 getValue()
的函數(shù)
對于一個可變屬性(即 var 聲明的),委托對象同時提供setValue()
、 getValue()
函數(shù)
類委托
可以通過類委托的模式來減少繼承
類委托的,編譯器會優(yōu)先使用自身重寫的函數(shù),而不是委托對象的函數(shù)
interface Base {
fun print()
}
class BaseImpl(val x: Int) : Base {
override fun print() {
print(x)
}
}
// Derived 的 print 實現(xiàn)會通過構造參數(shù)中的 b 對象來完成。
class Derived(b: Base) : Base by b
Kotlin 標準函數(shù)
使用時可以通過簡單的規(guī)則作出一些判斷:
-
返回自身 -> 從 apply 和 also 中選
-
作用域中使用 this 作為參數(shù) ----> 選擇 apply
-
作用域中使用 it 作為參數(shù) ----> 選擇 also
-
-
不需要返回自身 -> 從 run 和 let 中選擇
-
作用域中使用 this 作為參數(shù) ----> 選擇 run
-
作用域中使用 it 作為參數(shù) ----> 選擇 let
-
apply 適合對一個對象做附加操作的時候
let 適合配合空判斷的時候 (最好是成員變量,而不是局部變量,局部變量更適合用 if )
with 適合對同一個對象進行多次操作的時候
課后題
下面的代碼會輸出什么
data class User
fun main(){
val user = User()
val copy = user.copy()
println(user == copy)
println(user === copy)
}
此代碼在 Kotlin 中定義了一個名為 User 的數(shù)據(jù)類,然后創(chuàng)建了一個 User 實例 user 并對其進行了復制,創(chuàng)建了另一個實例 copy。然后,它打印了兩個比較的結果:
- user == copy:此行會輸出 true,因為 user 和 copy 是具有相同屬性值和狀態(tài)的實例。
- user === copy:此行會輸出 false,因為雖然 user 和 copy 具有相同的屬性值和狀態(tài),但它們是兩個不同的對象,在內存中占據(jù)不同的位置。=== 操作符在 Kotlin
中用于比較兩個對象的引用是否相等,而不僅僅是它們的屬性值。
- 【作文題】 聲明一個變量 call 寫一個「傳入?yún)?shù)類型」是 Request 類型,「返回值類型」是 Response 類型的「函數(shù)類型聲明」
val call : /* 函數(shù)類型聲明 */
可以使用 Kotlin 來聲明一個函數(shù)類型,該類型接受一個 Request 類型的參數(shù)并返回一個 Response 類型的結果。下面是如何聲明這樣的函數(shù)類型:文章來源:http://www.zghlxwxcb.cn/news/detail-736663.html
val call: (Request) -> Response
這里,我們創(chuàng)建了一個名為 CallType 的類型別名,它表示一個接受 Request 類型參數(shù)并返回 Response
類型結果的函數(shù)。你可以根據(jù)實際需要更改 Request 和 Response 類型。文章來源地址http://www.zghlxwxcb.cn/news/detail-736663.html
到了這里,關于Android開發(fā)知識學習——Kotlin進階的文章就介紹完了。如果您還想了解更多內容,請在右上角搜索TOY模板網以前的文章或繼續(xù)瀏覽下面的相關文章,希望大家以后多多支持TOY模板網!