1. 程式人生 > >Kotlin系列之變數和常量

Kotlin系列之變數和常量

標籤: Kotlin      變數      屬性     var與val區別      自定義屬性訪問器     智慧型別推斷

目錄:

簡述:

Kotlin基礎系列第二篇,之前記得有過第一篇算是Kotlin的基礎語法的入門篇,把kotlin的基本語法規範,基礎內容都過了一遍。接下來就是一一詳解。這講所說的是Kotlin的變數,主要會對以下內容做介紹:

1、變數基本定義

2、var和val的區別

3、智慧型別推斷

4、自定義屬性訪問器

5、var是可變的而val一定是不可變的嗎

一、Kotlin與Java中變數和常量 使用對比

  • 1、在Java中定義一個變數和常量

     public String name = "Mikyou";//定義變數
    
     public final int age = 18;//final定義常量
    
  • 2、在Kotlin中定義一個變數和常量

    var name: String = "Mikyou"
    
    val age: Int = 18
    

    或者

    var name = "Mikyou"
    
    val age = 18

總結: 由以上的對比可得出幾個點

1、Kotlin定義一個變數和常量比Java更簡潔和靈活

2、Kotlin中擁有型別推斷的機制,當一個變數或者常量初始化的時候可以省略型別的宣告,它會根據初始化值的型別來作為變數的型別。

3、Kotlin宣告變數和常量都必須使用var(變數),val(常量)關鍵字開頭,然後再是名稱,最後才是型別(如果有初始化值型別可以直接省略)

4、Kotlin相比Java預設的訪問修飾符是public,而Java中是default

5、Java中一般都是以型別開頭然後再是名稱,並且型別是不可以省略的;這樣的操作在Kotlin中是不行的。因為在Kotlin中型別是可以省略的,也就是型別相對比較弱化的,所以Kotlin會把型別放在最後,一般含有初始化值就會把在後面的型別宣告省略。

二、Kotlin的變數和常量用法

     var name: String
= "Mikyou" var address: String?//如果這個變數沒有初始化,那麼需要顯示宣告型別並且指明型別是否可null address = "NanJing" val age: Int = 18

或者

    var name = "Mikyou"

    val age = 18
  • 1、變數和常量宣告必須以“var”和“val”關鍵字開頭。
  • 2、 變數和常量的結構: (var 或者 val) 名稱 :(分割逗號) 變數型別 = 初始化值。
  • 3、 智慧型別轉換(編譯器提示為smart cast),如果變數或常量含有初始值可以省略型別,編譯器會預設分析出將初始化值的型別作為變數和常量型別。
  • 4、如果變數沒有初始化,那麼需要顯示宣告型別並且需要指明型別是否可null。

三、Kotlin的自定義屬性訪問器

在Kotlin中屬性是頭等特性,它習慣於用一個屬性去替代Java中的欄位和setter,getter方法。而Kotlin中的set、get訪問器相當於Java中的setter,getter方法。Kotlin有個新的特性就是可以去定義一個類中屬性的訪問器包括setter,getter訪問器。該特性十分適用於需要經過多個屬性邏輯計算得出的一個新的屬性。那麼邏輯計算的過程操作不需要像Java一樣開一個方法來實現。可以直接在屬性訪問器中進行邏輯運算。

  • 1、自定義get屬性訪問器

    在Java中實現:

    
    public class Rectangle{
    
      private float width;5
      private float height;
    
      public Rectangle(float width, float height){
          this.width = width;
          this.height = height;
      }
    
      public boolean isSquare{//在java中實現一個方法進行相關的邏輯計算
          return width == height;
      }
    
    }
    
    

    在Kotlin中實現:

    
    class Rectangle(width: Float, height: Float){
      val isSquare: Boolean//在Kotlin中只需要一個屬性就能解決,重新定義了isSquare的getter屬性訪問器,訪問器中可以寫入具體邏輯程式碼。
       get() {
          return width == height 
       }
    }
    
  • 2、自定義set屬性訪問器
    在Java中實現Android中的一個自定義View中的setter方法。

    public class RoundImageView extends ImageView{
        ...
      public void setBorderColor(int color){
         mColor = color;
         invalidate();
      }
        ...
    }
    

    在Kotlin中實現Android中的一個自定義View中的set屬性訪問器。

    
    class RoundImageView @JvmOverloads constructor(context: Context, attributeSet: AttributeSet? = null, defAttrStyle: Int = 0)
    : ImageView(context, attributeSet, defAttrStyle) {
    
     var mBorderColor: Int 
        set(value) {//自定義set屬性訪問器
            field = value
            invalidate()
        }
    }
    

四、Kotlin中的var和val區別

  • 1、var(來自於variable)可變引用。並且被它修飾的變數的值是可以改變,具有可讀和可寫許可權,相當於Java中非final的變數。

  • 2、val(來自於value)不可變引用。並且被它修飾的變數的值一般情況初始化一遍後期不能再次否則會丟擲編譯異常(這句話有待商榷,這個問題的討論和求證請看Kotlin中val不可變與可讀的討論),相當於Java中的final修飾的常量。

  • 3、在Kotlin開發過程中儘可能多的使用val關鍵字宣告所有的Kotlin的變數,僅僅在一些特殊情況使用var,我們都知道在Kotlin中函式是頭等公民,並且加入很多函數語言程式設計內容,而使用不可變的引用的變數使得更加接近函數語言程式設計的風格。

  • 4、需要注意的是val引用的本身是不可變的,但是它指向的物件可能是可變的(這個問題的討論和求證請檢視Kotlin中val不可變與可讀的討論)。

  • 5、var關鍵字允許改變自己的值,但是它的型別卻是無法改變的。

五、Kotlin中val不可變與可讀的討論

由於Kotlin是一門新的語言,我們在學習的過程中經常習慣性的去記住一些所謂定理,而沒有去真正深究為什麼是這樣。比如拿今天的議題來說,相信很多的人都這樣認為(剛開始包括我自己)var修飾的變數是可變的,而val修飾的變數是不可變的。然後學完Kotlin的自定義屬性訪問器就會覺得是有問題的。

然後去看一些國外的部落格,雖然有講述但是看完後更讓我懵逼的是val修飾的變數的值是可以變化的可讀的,並且底層的引用也是變化的。前面那句確實可以理解,後面一句還是保留意見。於是乎就開始寫demo認證。
引用國外部落格的一句原話”But can we say that val guarantees that underlying reference to the object is immutable? No…” 部落格源地址

  • 1、val不可變與可讀的假設

    假設一: 在Kotlin中的val修飾的變數不能說不可變的,只能說val修飾變數的許可權是可讀的。

    假設二: 在Koltin中的val修飾的變數的引用是不可變的,但是指向的物件是可變的。

  • 2、 val不可變與可讀的論證

    論證假設一: 我們在Kotlin的開發過程中,一般是使用了val修飾的變數就不能再次被賦值了,否則就會丟擲編譯時的異常。但是不能再次被賦值不代表它是不可變的。因為Kotlin與Java不一樣的是多了個自定義屬性訪問器的特性。這個特性貌似就和val修飾的變數是不可變的矛盾了。而Java中不存在這個問題,如果使用了final修飾的變數,沒有所謂自定義訪問器概念。

    fun main(args: Array<String>) {
        val name = "Hello Kotlin"
        name = "Hello Java"
    }
    

    print error:

    Error:(8, 5) Kotlin: Val cannot be reassigned

    定義get屬性訪問器例子

    package com.mikyou.kotlin
    
    import java.util.*
    
    /**
     * Created by mikyou on 2018/2/7.
     */
    
    class RandomNum {
        val num: Int
            get() = Random().nextInt()
    }
    
    fun main(args: Array<String>) {
        println("the num is ${RandomNum().num}")
    }
    

    print result:

    the num is -1411951962
    the num is -1719429461

    總結: 由以上的例子可以說明假設一是成立的,在Kotlin中的val修飾的變數不能說是不可變的,而只能說僅僅具有可讀許可權。

    論證假設二: 由論證一,我們知道Kotlin的val修飾的變數是可變的,那它的底層引用是否是可變的呢?國外一篇部落格說引用是可變的,真是這樣嗎?通過一個例子來說明。

    User類:

    package com.mikyou.kotlin.valtest
     open class User() {
         var name: String? = "test"
         var age: Int = 18
         var career: String? = "Student"
    }

    Student類:

    class Student() : User()

    Teacher類:

    class Teacher() : User()

    Customer介面:

    interface Customer {
    val user: User//注意: 這裡是個val修飾的User例項引用
    }

    VipCustomer實現類:

    class VipCustomer : Customer {
    override val user: User
        get() {
    //            return Student().apply {
    //                name = "mikyou"
    //                age = 18
    //                career = "HighStudent"
    //            }
            return Teacher().apply { //看到這裡很多人肯定認為,底層引用也會發生改變,畢竟Student, Teacher是不同的物件了。但是事實是這樣的嗎?
                name = "youkmi"
                age = 28
                career = "HighTeacher"
            }
        }
    }

    測試:

    fun main(args: Array<String>) = VipCustomer().user.run {
    println("my name is $name, I'm $age years old, my career is $career, my unique hash code is ${hashCode()} ")
    }
    

    print result:

    my name is mikyou, I’m 18 years old, my career is HighStudent, my unique hash code is 666988784

    切換到Teacher

    my name is youkmi, I’m 28 years old, my career is HighTeacher, my unique hash code is 666988784

    總結: 由以上的例子可以說明假設二是成立的,兩個不同的物件hashCode一樣說明,user的引用地址不變的,而變化的是引用指向的物件是可以變化的。

歡迎關注Kotlin開發者聯盟,這裡有最新Kotlin技術文章,每週會不定期翻譯一篇Kotlin國外技術文章。如果你也喜歡Kotlin,歡迎加入我們~~~