![](/img/trans.png)
[英]Kotlin variable initialization for child class behaves weird for initializing variable with value 0
[英]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)
}
}
我將用兩個日期實例化這個,其中一個是參考日期,然后確定該日期是在參考日期之前還是之后。 但是,在執行過程中,我發現在某些情況下 isBefore
和isAfter
仍然為false,與它們的價值無關,除非我逐步調試程序。 因此,顯然init
在構造函數之后不被調用,只是延遲了足夠長的時間以致於無法設置我的值?
我isBefore
isAfter
在getters中計算isBefore
和isAfter
:
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.