欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

kotlin中object關(guān)鍵字的三種使用場(chǎng)景

 更新時(shí)間:2020年06月01日 09:20:11   作者:王曉清  
這篇文章主要給大家介紹了關(guān)于kotlin中object關(guān)鍵字的三種使用場(chǎng)景,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家學(xué)習(xí)或者使用kotlin具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來一起學(xué)習(xí)學(xué)習(xí)吧

前言

object是Kotlin中的一個(gè)重要的關(guān)鍵字,也是Java中沒有的。object主要有以下三種使用場(chǎng)景:

  • 對(duì)象聲明(Object Declaration)
  • 伴生對(duì)象(Companion Object)
  • 對(duì)象表達(dá)式(Object Expression)

下面就一一介紹它們所表示的含義、用法以及注意點(diǎn),保證你在看完本篇之后就可以完全掌握object關(guān)鍵字的用法。

1. 對(duì)象聲明(Object Declaration)

語法含義:將類的聲明和定義該類的單例對(duì)象結(jié)合在一起(即通過object就實(shí)現(xiàn)了單例模式)

基本示例

object RepositoryManager{
 fun method(){
  println("I'm in object declaration")
 }
}

即將class關(guān)鍵字替換為object關(guān)鍵字,來聲明一個(gè)類,與此同時(shí)也聲明它的一個(gè)對(duì)象。只要編寫這么多代碼,這個(gè)類就已經(jīng)是單例的了。

使用

a. 在Kotlin中:

fun main(args: Array<String>) {
 RepositoryManager.method()
}

像在Java中調(diào)用靜態(tài)方法(在kotlin中沒有靜態(tài)方法)一樣去調(diào)用其中定義的方法,但實(shí)際上是使用RepositoryManager類的單例對(duì)象去調(diào)用實(shí)例方法。如果對(duì)此還不能理解,可以看看下面對(duì)在Java中去使用的說明。

b. 在Java中:

public class JavaTest {
 public static void main(String[] args) {
  RepositoryManager.INSTANCE.method();
 }
}

換句話說,object declaration的類最終被編譯成:一個(gè)類擁有一個(gè)靜態(tài)成員來持有對(duì)自己的引用,并且這個(gè)靜態(tài)成員的名稱為INSTANCE,當(dāng)然這個(gè)INSTANCE是單例的,故這里可以這么去使用。如果用Java代碼來聲明這個(gè)RepositoryManager的話,可以有如下代碼:

class RepositoryManager{
 private RepositoryManager(){}
 public static final RepositoryManager INSTANCE = new RepositoryManager();

}

4) 注意點(diǎn):

盡管和普通類的聲明一樣,可以包含屬性、方法、初始化代碼塊以及可以繼承其他類或者實(shí)現(xiàn)某個(gè)接口,但是它不能包含構(gòu)造器(包括主構(gòu)造器以及次級(jí)構(gòu)造器)
它也可以定義在一個(gè)類的內(nèi)部:

 class ObjectOuter {
  object Inner{
   fun method(){
    println("I'm in inner class")
   }
  }
 }
 fun main(args: Array<String>) {
  ObjectOuter.Inner.method()
 }

2、伴生對(duì)象(Companion object)

在闡述伴生對(duì)象之前,首先我們要明確一點(diǎn):在Kotlin中是沒有static關(guān)鍵字的,也就是意味著沒有了靜態(tài)方法和靜態(tài)成員。那么在kotlin中如果要想表示這種概念,取而代之的是包級(jí)別函數(shù)(package-level function)和我們這里提到的伴生對(duì)象。至于它們之間的區(qū)別,不急,我們后面再說。

語法形式:

class A{
 companion object 伴生對(duì)象名(可以省略){
  //define method and field here
 }
}

基本示例:

class ObjectTest {

 companion object MyObjec{

  val a = 20

  fun method() {
   println("I'm in companion object")
  }
 }
}

使用:

a. 在Kotlin中:

fun main(args: Array<String>) {
 //方式一
 ObjectTest.MyObject.method()
 println(ObjectTest.MyObject.a)

 //方式二(推薦方式)
 ObjectTest.method()
 println(ObjectTest.a)
}

在這里請(qǐng)注意:在定義(定義時(shí)如果省略了伴生對(duì)象名,那么編譯器會(huì)為其提供默認(rèn)的名字Companion)和調(diào)用時(shí)伴生對(duì)象名是可以省略的。而且在方式二中,注意調(diào)用形式,是通過類名.方法名()的形式進(jìn)行的,我們?cè)跊]有生成ObjectTest類的對(duì)象時(shí),調(diào)用了定義其內(nèi)部伴生對(duì)象中定義的屬性和方法,是不是類似Java中的靜態(tài)方法的概念。

通過現(xiàn)象看本質(zhì)

通過javap命令,讓我們看看其生成的字節(jié)碼:

注意紅框中,這個(gè)MyObject成員變量的類型,是使用

MyObject這個(gè)內(nèi)部類。注意它這里并沒有外部類的引用,說明是以靜態(tài)內(nèi)部類的形式存在的。

還記得我們?cè)谇懊孢z留的問題:同樣都可以用來替代Java中的static的概念,那么在伴生對(duì)象中定義的方法和包級(jí)別函數(shù)有什么區(qū)別呢?

先來反編譯一個(gè)包含包級(jí)別函數(shù)的kt文件(或者說是類):

可以看出,一個(gè)名叫ObjectTest2.kt文件,實(shí)際上最終會(huì)生成一個(gè)名叫ObjectTest2Kt的類,而在這個(gè)kt文件中定義的頂級(jí)函數(shù)(包級(jí)別函數(shù))是作為這個(gè)類的靜態(tài)方法的形態(tài)存在的。

那么現(xiàn)在可以回答遺留的問題了:實(shí)際上就是平級(jí)類(姑且稱之)中的靜態(tài)方法和靜態(tài)內(nèi)部類中的方法的區(qū)別,因?yàn)殪o態(tài)內(nèi)部類中的方法是可以訪問外部類中定義的static方法和成員的,哪怕是private的(包括私有構(gòu)造器,我們常用的基于靜態(tài)內(nèi)部類實(shí)現(xiàn)的單例模式就是基于這一點(diǎn)),而平級(jí)類中方法是訪問不到當(dāng)前類中靜態(tài)的private成員的。如果你覺得文字這么描述還不夠直觀,那么我們來看下面這一張圖(盜自Kotlin in action):

@JvmStatic注解:我們把前面定義的method方法上加上此注解,重新build工程,然后再來反編譯ObjectTest和ObjectTest$MyObject這個(gè)兩個(gè)類,看會(huì)有什么變化。

對(duì)于這個(gè)靜態(tài)內(nèi)部類而言,加與不加@JvmStatic注解其類的結(jié)構(gòu)是沒有變化的。但是對(duì)于目標(biāo)類而言,很明顯多了一個(gè)靜態(tài)方法,這樣我們就不難理解@JvmStatic注解的作用了:將伴生對(duì)象類中定義的實(shí)例方法和屬性,添加到目標(biāo)類中,并且以靜態(tài)的形式存在。

對(duì)于伴生對(duì)象,最后再補(bǔ)充一點(diǎn):一個(gè)類的伴生對(duì)象只能有一個(gè)。仔細(xì)想想也很好理解,伴生對(duì)象的名稱是可以省略的。如果允許對(duì)應(yīng)多個(gè)伴生對(duì)象,那么我們?cè)诙鄠€(gè)伴生對(duì)象中都定義了一模一樣的函數(shù),在調(diào)用時(shí)到底是使用哪個(gè)伴生對(duì)象的方法呢?就會(huì)產(chǎn)生歧義,這樣就不難理解這條語法規(guī)定了。

3、對(duì)象表達(dá)式(Object Expression)

Java的匿名內(nèi)部類回顧:

在去學(xué)習(xí)對(duì)象表達(dá)式之前,我們先來回顧一下Java中的匿名內(nèi)部類。

interface Contents {
 void absMethod();
}
public class Hello {

 public Contents contents() {
  return new Contents() {
   
   @Override
   public void absMethod() {
    System.out.println("method invoked...");
   }
  };
 }

 public static void main(String[] args) {

  Hello hello = new Hello();
  hello.contents().absMethod(); //打印method invoked...
 }
}
``` new Contents()

這個(gè)contents()方法返回的是一個(gè)匿名內(nèi)部類的對(duì)象,這個(gè)匿名內(nèi)部類實(shí)現(xiàn)了Contents接口。這些代碼很熟悉,不多說了。現(xiàn)在提出兩個(gè)局限性問題:

a. 如果在匿名內(nèi)部類中新添加了一些屬性和方法,那么在外界是無法調(diào)用的

return new Contents() {
private int i = 1;
  public int value() {
   return i;
  }

  @Override
  public void absMethod() {
   System.out.println("method invoked...");
  }
 };

public static void main(String[] args) {
 Hello hello = new Hello();
 hello.contents().absMethod();
 hello.contents().value(); //Cannot resolve method 'value()'
}

當(dāng)你想使用這個(gè)value方法時(shí),編譯器會(huì)報(bào)錯(cuò)。也好理解,就是多態(tài)的知識(shí),父類型的引用是無法知曉子類添加方法的存在的。

b. 一個(gè)匿名內(nèi)部類肯定是實(shí)現(xiàn)了一個(gè)接口或者是繼承一個(gè)類,并且只能是一個(gè),用數(shù)學(xué)術(shù)語說是“有且只有一個(gè)”

2) 語法形式:

object [ : 接口1,接口2,類型1, 類型2]{}    //中括號(hào)中的可省略

3) 使用示例:

a. 實(shí)現(xiàn)一個(gè)接口或類

interface AA {
fun a()
}
fun main(args: Array) {
val aa = object : AA {
 override fun a() {
  println("a invoked")
 }
}

aa.a()
}

b. 不實(shí)現(xiàn)任何接口和類,并且在匿名內(nèi)部類中添加方法

fun main(args: Array) {
val obj = object {
 fun a() {
  println("a invoked")
 }
}

obj.a() //打?。篴 invoked

}

從這個(gè)例子可以看出,前面我們提到的Java匿名內(nèi)部類的第一個(gè)局限的地方在Kotlin中就不存在了,新添加的方法也是可以調(diào)用的

c. 實(shí)現(xiàn)多個(gè)接口和類

fun main(args: Array) {
val cc = object : AA, BB() {
override fun a() {
 }

 override fun b() {

 }

}

cc.a()
cc.b()
}

從這個(gè)例子可以看出,前面我們提到的Java匿名內(nèi)部類的第二個(gè)局限性在kotlin中也不存在

4) 使用注意點(diǎn):

這是Kotlin官方文檔上的一段話:匿名對(duì)象只有定義成局部變量和private成員變量時(shí),才能體現(xiàn)它的真實(shí)類型。如果你是將匿名對(duì)象作為public函數(shù)的返回值或者是public屬性時(shí),你只能將它看做是它的父類,當(dāng)然你不指定任何類型時(shí)就當(dāng)做Any看待。這時(shí),你在匿名對(duì)象中添加的屬性和方法是不能夠被訪問的。

再來舉個(gè)例子幫助大家理解:

class MyTest {
private val foo = object {
 fun method() {
  println("private")
 }
}

val foo2 = object {
 fun method() {
  println("public")
 }
}

fun m() = object {
 fun method(){
  println("method")
 }
}

fun invoke(){

 val local = object {
  fun method(){
   println("local")
  }
 }

 local.method() //編譯通過
 foo.method() //編譯通過
 foo2.method() //編譯通不過
 m().method() //編譯通不過
}
}

5) 關(guān)于在匿名對(duì)象中訪問同一作用下定義的局部變量的問題:

在Java中,如果在匿名內(nèi)部類中訪問外部定義的局部變量,那么該局部變量必須使用final關(guān)鍵字進(jìn)行修飾,至于為什么大家可以看我之前的一篇博文。而在Kotlin中,這條限制沒有了,看下面的例子:

var a = 1
val obj = object {
fun method() {
a++
}
}
obj.method()
println(a) //打印出2

再來解釋一下:在Java中,實(shí)際上在method方法中使用的a實(shí)際上是局部變量a的一份拷貝,而不是它本身。而在Kotlin最終也是要編譯成字節(jié)碼供JVM去執(zhí)行,所以本質(zhì)上它是不會(huì)違背這一點(diǎn)的。那么它是怎么處理的呢?

當(dāng)你訪問的局部變量是val時(shí),那么也是很Java一樣,持有的是一份拷貝;而當(dāng)你是一個(gè)可變變量(var)時(shí),它的值是被存儲(chǔ)在Ref這個(gè)類的實(shí)例成員中,Ref變量是final的,而他其中的成員變量是可以改變的。反編譯后是可以看到Ref的身影的。

這里還有段有點(diǎn)意思的代碼,給大家貼出:

fun tryToCountButtonClicks(button: Button): Int{
var clicks = 0

button.setOnClickListener{
 clicks++
}

return clicks
}

button是個(gè)按鈕,這段代碼的本意上是想要統(tǒng)計(jì)Button被點(diǎn)擊的次數(shù)。但是這個(gè)函數(shù)的返回值始終是0,哪怕你點(diǎn)擊再多次。因?yàn)槟銓?duì)局部變量clicks值得修改是異步的,而此函數(shù)的返回值是在執(zhí)行時(shí)就確定了的,就是你的值還沒有被修改,函數(shù)已經(jīng)返回了。如果真的想統(tǒng)計(jì)點(diǎn)擊次數(shù),可以將clicks定義成類的成員變量。

4. 對(duì)比object declaration、Companion object以及object expression的初始化時(shí)機(jī):

a. object declaration:當(dāng)?shù)谝淮卧L問它時(shí)才初始化,是一種懶初始化

b. Companion object:當(dāng)它對(duì)應(yīng)的類被加載后,它才初始化,類似Java中的靜態(tài)代碼塊

c. object expression:一旦它被執(zhí)行,立馬初始化

至此,關(guān)于Kotlin中的object關(guān)鍵字的使用就介紹完了,希望大家能有所收獲~

總結(jié)

到此這篇關(guān)于kotlin中object關(guān)鍵字的三種使用場(chǎng)景的文章就介紹到這了,更多相關(guān)kotlin object關(guān)鍵字使用場(chǎng)景內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • android自定義view制作圓形進(jìn)度條效果

    android自定義view制作圓形進(jìn)度條效果

    這篇文章主要為大家詳細(xì)介紹了android自定義view制作圓形進(jìn)度條效果的相關(guān)資料,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2017-01-01
  • Android 操作系統(tǒng)獲取Root權(quán)限 原理詳細(xì)解析

    Android 操作系統(tǒng)獲取Root權(quán)限 原理詳細(xì)解析

    許多機(jī)友新購(gòu)來的Android機(jī)器沒有破解過Root權(quán)限,無法使用一些需要高權(quán)限的軟件,以及進(jìn)行一些高權(quán)限的操作,其實(shí)破解手機(jī)Root權(quán)限是比較簡(jiǎn)單及安全的,破解Root權(quán)限的原理就是在手機(jī)的/system/bin/或/system/xbin/目錄下放置一個(gè)可執(zhí)行文件“su”
    2013-10-10
  • Android開發(fā)中通過手機(jī)號(hào)+短信驗(yàn)證碼登錄的實(shí)例代碼

    Android開發(fā)中通過手機(jī)號(hào)+短信驗(yàn)證碼登錄的實(shí)例代碼

    最近在開發(fā)一個(gè)android的項(xiàng)目,需要通過獲取手機(jī)驗(yàn)證碼來完成登錄功能,接下來通過實(shí)例代碼給大家分享手機(jī)號(hào)+短信驗(yàn)證碼登錄的實(shí)現(xiàn)方法,需要的的朋友參考下吧
    2017-05-05
  • Android開發(fā)實(shí)現(xiàn)生成excel的方法詳解

    Android開發(fā)實(shí)現(xiàn)生成excel的方法詳解

    這篇文章主要介紹了Android開發(fā)實(shí)現(xiàn)生成excel的方法,結(jié)合實(shí)例形式詳細(xì)分析了Android生成Excel的具體步驟與存儲(chǔ)、導(dǎo)入、添加等相關(guān)操作技巧,需要的朋友可以參考下
    2017-10-10
  • FFmpeg Principle學(xué)習(xí)open_output_file打開輸出文件

    FFmpeg Principle學(xué)習(xí)open_output_file打開輸出文件

    這篇文章主要為大家介紹了FFmpeg Principle學(xué)習(xí)open_output_file打開輸出文件示例解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-10-10
  • Android studio4.1更新后出現(xiàn)的問題詳解

    Android studio4.1更新后出現(xiàn)的問題詳解

    這篇文章主要介紹了Android studio4.1更新后出現(xiàn)的問題詳解,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-10-10
  • Android獲取手機(jī)配置信息具體實(shí)現(xiàn)代碼

    Android獲取手機(jī)配置信息具體實(shí)現(xiàn)代碼

    下面為大家介紹下使用android獲取手機(jī)配置信息的具體過程,感興趣的朋友可以參考下哈,希望對(duì)你有所幫助
    2013-06-06
  • Android四大組件之廣播BroadcastReceiver詳解

    Android四大組件之廣播BroadcastReceiver詳解

    Android開發(fā)的四大組件分別是:活動(dòng)(activity),用于表現(xiàn)功能;服務(wù)(service),后臺(tái)運(yùn)行服務(wù),不提供界面呈現(xiàn);廣播接受者(Broadcast Receive),勇于接收廣播;內(nèi)容提供者(Content Provider),支持多個(gè)應(yīng)用中存儲(chǔ)和讀取數(shù)據(jù),相當(dāng)于數(shù)據(jù)庫,本篇著重介紹廣播組件
    2021-11-11
  • android studio實(shí)現(xiàn)簡(jiǎn)單的計(jì)算器(無bug)

    android studio實(shí)現(xiàn)簡(jiǎn)單的計(jì)算器(無bug)

    這篇文章主要為大家詳細(xì)介紹了android studio實(shí)現(xiàn)簡(jiǎn)單計(jì)算器,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2020-08-08
  • Android自定義Drawable實(shí)現(xiàn)圓形和圓角

    Android自定義Drawable實(shí)現(xiàn)圓形和圓角

    這篇文章主要為大家詳細(xì)介紹了Android自定義Drawable實(shí)現(xiàn)圓形和圓角,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2017-09-09

最新評(píng)論