簡體   English   中英

用Kotlin初始化值

[英]Value initialization with Kotlin

我想我發現了一個奇怪的邊緣情況:

我所擁有的:

class Day constructor(cal: Calendar, refCal: Calendar) {
    val cal: Calendar
    val isBefore: Boolean
    val isAfter: Boolean

    init {
        this.cal = cal.clone() as Calendar
        isBefore = 0 < cal.compareTo(refCal)
        isAfter = 0 > cal.compareTo(refCal)
    }
}

我將用兩個日期實例化這個,其中一個是參考日期,然后確定該日期是在參考日期之前還是之后。 但是,在執行過程中,我發現在某些情況下 isBeforeisAfter仍然為false,與它們的價值無關,除非我逐步調試程序。 因此,顯然init在構造函數之后不被調用,只是延遲了足夠長的時間以致於無法設置我的值?

isBefore isAfter在getters中計算isBeforeisAfter

class Day constructor(cal: Calendar, refCal: Calendar) {
    val cal: Calendar

    init {
        this.cal = cal.clone() as Calendar
        this.refCal = refCal.clone() as Calendar
    }

    val isBefore: Boolean
        get() { return 0 < cal.compareTo(refCal) }
    val isAfter: Boolean
        get() { return 0 > cal.compareTo(refCal) }
}

我想知道我的假設是否正確,是否有一種方法可以在使用init對其進行初始化之前調用它,如果可以的話,是否有一種方法可以減輕這種情況。


通話示例:

fun setDates(refDate: Calendar) {
    val cal = Calendar.getInstance()
    cal.set(refDate.get(Calendar.YEAR), refDate.get(Calendar.MONTH), refDate.get(Calendar.DAY_OF_MONTH), 0, 0, 0)

    cal.set(Calendar.DAY_OF_WEEK, Calendar.MONDAY)
    val monday = Day(cal, refDate)
    //...

據我所知, init塊將在主構造函數中執行,因此您的原始類Day應該很好。 您可以只刪除init塊,然后直接使用屬性的聲明來分配值。

我只看到兩個問題,一個是:

但是,我在執行時發現在某些情況下isBefore和isAfter仍然為false

如果cal.compareTo(refCal)返回0那根本就不足為奇。
或者,如果在兩行執行之間refCal的值發生了變化

isBefore = 0 < cal.compareTo(refCal)
isAfter = 0 > cal.compareTo(refCal)

第二個問題是Day實現,當您為屬性聲明一個getter時

val isBefore: Boolean
    get() { return 0 < cal.compareTo(refCal) }

您每次讀取該屬性時都在比較該值,這意味着,如果refCal屬性的值更改,則isBefore的值可以在同一Day實例中很容易地更改。 如果您只想讀取refCal的值並分配isBefore ,則應在初始化屬性時,在init塊中或在聲明中進行此操作(也可以省略類型並直接使用>運算符):

class Day constructor(cal: Calendar, refCal: Calendar) {
    private val cal = cal.clone() as Calendar
    val isBefore = cal > refCal
    val isAfter = cal < refCal
}

也許添加諸如val isEqual = !isBefore && !isAfter因為這兩個不是互斥的。

更新資料

我剛剛檢查了Kotlin 1.2.30,Intellij的Kotlin插件允許您查看編譯Kotlin類的字節碼(該操作稱為“ Show Kotlin Bytecode”)。 放在init塊中的代碼確實在主構造函數中執行。 例如,此類:

class Day(cal: Calendar)  {

    val cal: Calendar

    init {
        this.cal = cal.clone() as Calendar
    }
}

編譯此構造函數:

  // access flags 0x1
  public <init>(Ljava/util/Calendar;)V
    @Lorg/jetbrains/annotations/NotNull;() // invisible, parameter 0
   L0
    ALOAD 1
    LDC "cal"
    INVOKESTATIC kotlin/jvm/internal/Intrinsics.checkParameterIsNotNull (Ljava/lang/Object;Ljava/lang/String;)V
   L1
    LINENUMBER 3 L1
    ALOAD 0
    INVOKESPECIAL java/lang/Object.<init> ()V
   L2
    LINENUMBER 8 L2
    ALOAD 0
    ALOAD 1
    INVOKEVIRTUAL java/util/Calendar.clone ()Ljava/lang/Object;
    DUP
    IFNONNULL L3
    NEW kotlin/TypeCastException
    DUP
    LDC "null cannot be cast to non-null type java.util.Calendar"
    INVOKESPECIAL kotlin/TypeCastException.<init> (Ljava/lang/String;)V
    ATHROW
   L3
    CHECKCAST java/util/Calendar
    PUTFIELD Day.cal : Ljava/util/Calendar;
   L4
    RETURN
   L5
    LOCALVARIABLE this LDay; L0 L5 0
    LOCALVARIABLE cal Ljava/util/Calendar; L0 L5 1
    MAXSTACK = 5
    MAXLOCALS = 2

如您所見, Calendar.clone在此處被調用,因此您可以像使用Java中的構造函數一樣對待init

如果沒有主構造函數,例如:

class Day {
    constructor(cal: Calendar)
    constructor()

    val cal: Calendar

    init {
        this.cal = Calendar.getInstance()
    }
}

創建2個構造函數,並在每個構造函數中執行init塊的代碼。

  // access flags 0x1
  public <init>(Ljava/util/Calendar;)V
    @Lorg/jetbrains/annotations/NotNull;() // invisible, parameter 0
   L0
    ALOAD 1
    LDC "cal"
    INVOKESTATIC kotlin/jvm/internal/Intrinsics.checkParameterIsNotNull (Ljava/lang/Object;Ljava/lang/String;)V
   L1
    LINENUMBER 4 L1
    ALOAD 0
    INVOKESPECIAL java/lang/Object.<init> ()V
   L2
    LINENUMBER 10 L2
    ALOAD 0
    INVOKESTATIC java/util/Calendar.getInstance ()Ljava/util/Calendar;
    DUP
    LDC "Calendar.getInstance()"
    INVOKESTATIC kotlin/jvm/internal/Intrinsics.checkExpressionValueIsNotNull (Ljava/lang/Object;Ljava/lang/String;)V
    PUTFIELD Day.cal : Ljava/util/Calendar;
   L3
    RETURN
   L4
    LOCALVARIABLE this LDay; L0 L4 0
    LOCALVARIABLE cal Ljava/util/Calendar; L0 L4 1
    MAXSTACK = 4
    MAXLOCALS = 2

  // access flags 0x1
  public <init>()V
   L0
    LINENUMBER 5 L0
    ALOAD 0
    INVOKESPECIAL java/lang/Object.<init> ()V
   L1
    LINENUMBER 10 L1
    ALOAD 0
    INVOKESTATIC java/util/Calendar.getInstance ()Ljava/util/Calendar;
    DUP
    LDC "Calendar.getInstance()"
    INVOKESTATIC kotlin/jvm/internal/Intrinsics.checkExpressionValueIsNotNull (Ljava/lang/Object;Ljava/lang/String;)V
    PUTFIELD Day.cal : Ljava/util/Calendar;
   L2
    RETURN
   L3
    LOCALVARIABLE this LDay; L0 L3 0
    MAXSTACK = 4
    MAXLOCALS = 1

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM