Kotlin 4 构造,对象,修饰符,关键字,委托
注:當前文檔為Kotlin自學總結,若什么地方含義模糊不清,敬請指教,謝謝:-)。
目錄:- 構造函數- 對象- 匿名對象- 對象聲明- 對象表達式和對象聲明之間的語義差異- 修飾符- 關鍵字- 委托- 類委托- 屬性委托- 要求- 延遲性- 觀察者模式- 屬性映射- 局部委托 復制代碼構造函數 - 一個主構造多個次構造,主構造函數的所有的參數都有默認值
-
主構造:(類聲明之后)
//默認類聲明 + 主構造class ClazzName public constructor{}class ClazzName public @Inject constructor(val/var params1 : type = defultValue){//constructor可省略,有注解時必須存在//public 為可見性修飾符init {//init -> 初始化代碼塊,主構造的參數可以在初始化代碼塊使用}} 復制代碼 -
次構造:委托或間接委托給主構造,需要 this 關鍵字(也可有constructor前綴)
class Person(val name: String) {//類聲明 + 主構造constructor(name: String, parent: Person) : this(name) {//次構造,相當于添加參數或重新賦值name//... ...}} 復制代碼 -
創建一般實例 - 沒有new 關鍵字
val invoice = Invoice()val customer = Customer("Joe Smith") //創建使用匿名對象,對象聲明,單例請查看Kotlin-4.md 復制代碼
對象
一般對象的創建方式使用構造函數傳參創建.
1. 匿名對象
一般匿名對象的使用
window.addMouseListener(object : MouseAdapter() {override fun mouseClicked(e: MouseEvent) {// ……} }) 復制代碼多個繼承或實現并且需要傳參的匿名對象
open class A(x: Int) {public open val y: Int = x }interface B {……}val ab: A = object : A(1), B {override val y = 15 } 復制代碼沒有繼承或實現的匿名對象創建
fun foo() {val adHoc = object {var x: Int = 0var y: Int = 0}print(adHoc.x + adHoc.y) } 復制代碼公有函數返回值為匿名對象時,類型為Any,將不能訪問匿名對象的成員.
class C {// 私有函數,所以其返回類型是匿名對象類型private fun foo() = object {val x: String = "x"}// 公有函數,所以其返回類型是 Anyfun publicFoo() = object {val x: String = "x"}fun bar() {val x1 = foo().x // 沒問題val x2 = publicFoo().x // 錯誤:未能解析的引用“x”} } 復制代碼對象聲明
對象聲明只能在其他對象聲明或非內部類中.
//有繼承的單例對象聲明 object DataProviderManager : Parent() {fun registerDataProvider(provider: DataProvider) {// ……}val allDataProviders: Collection<DataProvider>get() = // …… }//直接調用 DataProviderManager.registerDataProvider(....) 復制代碼對象表達式和對象聲明之間的語義差異
對象表達式和對象聲明之間有一個重要的語義差別:
- 對象表達式是在使用他們的地方立即執行(及初始化)的 - 對象聲明是在第一次被訪問到時延遲初始化的 - 伴生對象的初始化是在相應的類被加載(解析)時,與 Java 靜態初始化器的語義相匹配 復制代碼修飾符
-
val和var
val 只讀;var 可變.(var默認創建getter,setter; val 默認創建 getter) 復制代碼 -
可見性修飾符
-
internal →代替→ default,意味著該成員只在相同模塊內可見。更具體地說, 一個模塊是編譯在一起的一套 Kotlin 文件:
一個 IntelliJ IDEA 模塊;一個 Maven 或者 Gradle 項目;一次 <kotlinc> Ant 任務執行所編譯的一套文件。 復制代碼 -
局部變量、函數和類不能有可見性修飾符。
關鍵字
-
this
-
在類的成員中,this 指的是該類的當前對象.
-
在擴展函數或者帶接收者的函數字面值中, this 表示在"."左側傳遞的接收者參數。
class A { // 隱式標簽 @Ainner class B { // 隱式標簽 @Bfun Int.foo() { // 隱式標簽 @fooval a = this@A // A 的 thisval b = this@B // B 的 thisval c = this // foo() 的接收者,一個 Intval c1 = this@foo // foo() 的接收者,一個 Intval funLit = lambda@ fun String.() {val d = this // funLit 的接收者}val funLit2 = { s: String ->// foo() 的接收者,因為它包含的 lambda 表達式// 沒有任何接收者val d1 = this}}}} 復制代碼
-
-
abstract 抽象
-
companion → static(不存在此關鍵字) 伴生對象
-
類沒有靜態方法。在大多數情況下,它建議簡單地使用包級函數。
-
需要訪問其他類內部的函數,可以把它寫成該類內對象聲明中的一員。
class MyClass {companion object Factory { //Factory名稱可以省略fun create(): MyClass = MyClass()}}//其他類中調用需要val instance = MyClass.create()//名稱省略后val x = MyClass.Companion 復制代碼
-
-
const 編譯時常量
請查看Kotlin-3.md 編譯時常量內容 復制代碼 -
lateinit 延遲初始化屬性使用
-
使用字段可以避免編譯時空檢查
-
只能與var配合使用
-
屬性類型不能為空或原生類型
-
可以在單元測試的@setUp函數中初始化;
-
初始化前訪問屬性會拋出"被訪問且沒有初始化"的異常.
public class MyTest {lateinit var subject: TestSubject@SetUp fun setup() {subject = TestSubject()}@Test fun test() {subject.method() // 直接解引用}} 復制代碼
-
委托
類委托
格式:
class A{fun aa()fun bb()... }class A1:A{override fun aa(){...}override fun bb(){...}... }class ClazzName(a:A):A by a{... }//使用 clazzName(A1()).aa() 復制代碼某個類通過關鍵字by,使用委托參數的方式、繼承的格式,調用自身沒有但該參數所在類標注的基類存在的所有公有函數的形式,叫做類委托.
原理:by 語句會將對應的委托對象進行內部存儲,編譯器將生成轉發給該對象的所有標注基類的方法。
interface Base {fun print() }class BaseImpl(val x: Int) : Base {override fun print() { print(x) } }class Derived(b: Base) : Base by b //Base為BaseImpl b的基類fun main(args: Array<String>) {val b = BaseImpl(10)Derived(b).print() // 輸出 10 } 復制代碼委托屬性
使用**by關鍵字,將屬性的getter、setter委托給函數或某個類的operator** 函數,
屬性委托要求
對于一個只讀屬性(即 val 聲明的),委托必須提供一個名為 getValue 的函數,該函數接受以下參數:
thisRef —— 必須與 屬性所有者 類型(對于擴展屬性——指被擴展的類型)相同或者是它的超類型, property —— 必須是類型 KProperty<*> 或其超類型, 這個函數必須返回與屬性相同的類型(或其子類型)。
對于一個可變屬性(即 var 聲明的),委托必須額外提供一個名為 setValue 的函數,該函數接受以下參數:
thisRef —— 同 getValue(), property —— 同 getValue(), new value —— 必須和屬性同類型或者是它的超類型。 getValue() 或/和 setValue() 函數可以通過委托類的成員函數提供或者由擴展函數提供。 當你需要委托屬性到原本未提供的這些函數的對象時后者會更便利。 兩函數都需要用 operator 關鍵字來進行標記。
委托類可以實現包含所需 operator 方法的 ReadOnlyProperty 或 ReadWriteProperty 接口之一。 這倆接口是在 Kotlin 標準庫中聲明的:
interface ReadOnlyProperty<in R, out T> {operator fun getValue(thisRef: R, property: KProperty<*>): T }interface ReadWriteProperty<in R, T> {operator fun getValue(thisRef: R, property: KProperty<*>): Toperator fun setValue(thisRef: R, property: KProperty<*>, value: T) } 復制代碼延遲性
延遲: (lazy() 是接受一個 lambda 并返回一個 Lazy 實例的函數,返回的實例可以作為實現延遲屬性的委托.)第一次調用 get() 會執行已傳遞給 lazy() 的 lamda 表達式并記錄結果, 后續調用 get() 只是返回記錄的結果。
延遲是具有同步鎖線程安全的,默認 LazyThreadSafetyMode.PUBLICATION傳入lazy(),使用 LazyThreadSafetyMode.NONE 模式, 它不會有任何線程安全的保證和相關的開銷。
val lazyValue: String by lazy {println("computed!")"Hello" }fun main(args: Array<String>) {println(lazyValue)println(lazyValue) } //輸出內容 //computed! //Hello //Hello 復制代碼委托的觀察者模式
Delegates.observable()和Delegates.vetoable()
Delegates.observable() 接受兩個參數:初始值和修改時處理程序(handler)。 每當我們給屬性賦值時會調用該處理程序(在賦值后執行)。它有三個 參數:被賦值的屬性、舊值和新值;
import kotlin.properties.Delegatesclass User {var name: String by Delegates.observable("<no name>") {//初始值prop, old, new -> //被賦值的屬性、舊值和新值println("$old -> $new")} }fun main(args: Array<String>) {val user = User()user.name = "first"user.name = "second" }//打印內容為 //<no name> -> first //first -> second 復制代碼Delegates.vetoable()可以截獲一個賦值并“否決”它,在屬性被賦新值生效之前會調用傳遞給 vetoable 的處理程序。
屬性存儲到映射 - 在一個映射(map)里存儲屬性的值。
class User(val map: Map<String, Any?>) {val name: String by mapval age: Int by map }val user = User(mapOf("name" to "John Doe","age" to 25 ))println(user.name) // Prints "John Doe" println(user.age) // Prints 25 復制代碼val -> Map, var -> MutableMap
局部委托點擊此處
本文參考自 Kotlin語言中心站
轉載于:https://juejin.im/post/5a32177e6fb9a0450167f9f5
總結
以上是生活随笔為你收集整理的Kotlin 4 构造,对象,修饰符,关键字,委托的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 使用nginx代理跨域,使用nginx代
- 下一篇: 【下一代核心技术DevOps】:(三)私