【问题标题】:How to initialize fields outside the constructor如何在构造函数之外初始化字段
【发布时间】:2019-10-29 06:30:14
【问题描述】:

我有一个在 Room 中使用的数据类。在类的开头有字符串 _dateControl 和 _timeCreate 形式的日期字段。类的主体中有 Long 类型的 dateControl 和 timeCreate 字段。通过 Retrofit 请求数据时,dateControl 和 timeCreate 字段是独立初始化的。但是如果我尝试声明一个类的实例,那么这些字段(dateControl 和 timeCreate)没有被初始化并且等于 0。

@Entity
class DetailNum(
    @SerializedName("id_ndt_res")
    @PrimaryKey val id: Int,
    @SerializedName("id_pr")
    val idEntUser: Int,
    @SerializedName("id_parts")
    val type: Int,
    @SerializedName("dt_controlya")
    var _dateControl: String,
    @SerializedName("number_part")
    var numDetail: String?,
    @SerializedName("god_izg")
    var yearCreate: Int,
    @SerializedName("id_zavods")
    var idFactory: Int,
    @SerializedName("time_create")
    var _timeCreate: String,
    @SerializedName("id_result")
    var resultControl: Int,
    @SerializedName("familiya_i_o_speca")
    var fioSpec: String?,
    @SerializedName("is_new_part")
    var isNew: Int,
    @SerializedName("is_from_pto")
    var isFromPto: Int,
    @SerializedName("is_not_kriterii_01_08_2013")
    var isNotKrit01082013: Int,
    @SerializedName("isLoaded")
    var isLoaded: Int = 0

) {
    public fun getSimpleDateStr() = SimpleDateFormat("dd.MM.yyyy").format(Date(dateControl))

    val strResultControl: String
        get() = resultControl.toString()

    var dateControl: Long = 0
        set(value) {
            val date = SimpleDateFormat("dd.MM.yyyy").parse(_dateControl)
            field = date.time
        }

    var timeCreate: Long = 0
        set(value) {
            val date = SimpleDateFormat("dd.MM.yyyy HH:mm:ss").parse(_timeCreate)
            field = date.time
        }
    var nameResult:String?=""

    fun getFirstCharNameResult() = if(!nameResult.isNullOrEmpty()) nameResult?.get(0)?.toUpperCase() else ""
}

尝试像这样初始化

var detailNum = DetailNum(0, 0, 0, DateUtils.getSimpleDateStr(Date()), "", 0, 0, DateUtils.getSimpleDateStr(Date()), 0,"", 0, 0, 0 )

为什么第二种情况下长日期字段没有初始化,如何初始化?我是Kotlin的新手,请解释一下,提前谢谢

【问题讨论】:

    标签: android class kotlin constructor


    【解决方案1】:

    dateControltimeCreate 等字段未在构造函数中初始化!如果不是某些框架,它们的设置器不会被自动调用。

    如果您希望在构造函数初始化后立即设置它们,您可以:

    1) .. 立即设置默认值

    val dateControl: Long = SimpleDateFormat("dd.MM.yyyy").parse(_dateControl).time
    

    2) .. 或使用init 如果操作需要更多代码或者您想将内部字段初始化收集在一起

    class DetailNum(...) {
    
       var dateControl: Long = 0
    
       init {
          dateControl = SimpleDateFormat("dd.MM.yyyy").parse(_dateControl).time
          ...
       }
    
    }
    

    更多关于构造函数和init的信息你可以找到here

    顺便说一句:你的 setter 根本不使用提供的值,所以实际上它们是无用的。

    【讨论】:

    • 原则上,一切都是正确的,但现在如果我执行 init{..} 并删除 setter,当我从 Room 获取查询时,dateControl 未初始化,只有在我这样做时才初始化: var detailNum = DetailNum(...)。与第一个选项相同(1)..立即设置默认值)
    • 我对Android和Room不熟悉,但我猜构造函数之外的那些字段也是由库设置并覆盖默认值的。如果是这种情况,一种解决方案是使用 @Ignore 注释这些字段,并使用 val dateControl : Int by lazy { ... } 懒惰地初始化它们。
    • @VNprk 你也可以覆盖getter get() = ...,它总是会生成新的和最新的值
    • 我需要var属性,但是lazy只能用于val属性
    • 感谢您的澄清,我意识到自己的错误,最终做了一个复杂的 getter 和 setter,没有 init 块
    【解决方案2】:

    对下面的变量使用lateinit

    lateinit var subject: TestSubject
    

    【讨论】:

    • 我需要 Long 类型变量,但原始类型不允许使用 lateinit 修饰符
    • 是的,我忘记了只有不可为空的非原始类型可能需要 lateinit 才能绕过类型安全系统。
    猜你喜欢
    • 1970-01-01
    • 2017-05-12
    • 2011-03-28
    • 2010-11-28
    • 2020-01-18
    • 1970-01-01
    • 2012-06-30
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多