我想我发现了一个奇怪的边缘情况:
我有什么:
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
在某些情况下仍然是 ,与它们的价值无关,除非我一步一步地进行使用调试器。所以,显然init
在构造函数之后被调用,只是延迟了我的值不能被设置?
我要解决的问题只是在getter中计算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)
//...
答案 0 :(得分:2)
据我所知,init
块将在主构造函数中执行,因此原始类Day
应该没问题。你可以删除init
块并直接使用属性的声明分配值。
我只看到两个问题,一个是:
但是,我在执行时发现的是isBefore和isAfter 在某些情况下仍然是假的
如果cal.compareTo(refCal)
返回0
,那将毫无意外。
或者,如果{2}行的执行之间refCal
的值发生了变化
isBefore = 0 < cal.compareTo(refCal)
isAfter = 0 > cal.compareTo(refCal)
第二个问题是你的第二个Day
实现,当你为属性
val isBefore: Boolean
get() { return 0 < cal.compareTo(refCal) }
您每次阅读该属性时都会比较该值,这意味着isBefore
的值很容易在同一个Day
实例中更改,如果值refCal
属性更改。如果您只想读取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类的字节码(该操作被称为&#34;显示Kotlin字节码&#34;)。您放在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