- mongodb - 在 MongoDB mapreduce 中,如何展平值对象?
- javascript - 对象传播与 Object.assign
- html - 输入类型 ="submit"Vs 按钮标签它们可以互换吗?
- sql - 使用 MongoDB 而不是 MS SQL Server 的优缺点
在 Kotlin 中,如果您不想在构造函数内或类体顶部初始化类属性,则基本上有以下两种选择(来自语言引用):
lazy()
is a function that takes a lambda and returns an instance ofLazy<T>
which can serve as a delegate for implementing a lazy property: the first call toget()
executes the lambda passed tolazy()
and remembers the result, subsequent calls toget()
simply return the remembered result.Example
public class Hello {
val myLazyString: String by lazy { "Hello" }
}
因此,无论在何处,第一次调用和随后的调用都将发送到 myLazyString
将返回 Hello
Normally, properties declared as having a non-null type must be initialized in the constructor. However, fairly often this is not convenient. For example, properties can be initialized through dependency injection, or in the setup method of a unit test. In this case, you cannot supply a non-null initializer in the constructor, but you still want to avoid null checks when referencing the property inside the body of a class.
To handle this case, you can mark the property with the lateinit modifier:
public class MyTest {
lateinit var subject: TestSubject
@SetUp fun setup() { subject = TestSubject() }
@Test fun test() { subject.method() }
}The modifier can only be used on var properties declared inside the body of a class (not in the primary constructor), and only when the property does not have a custom getter or setter. The type of the property must be non-null, and it must not be a primitive type.
那么,既然这两个选项都可以解决同一个问题,那么如何正确选择呢?
最佳答案
以下是 lateinit var
和 bylazy { ... }
委托(delegate)属性的显着区别:
lazy { ... }
委托(delegate)只能用于 val
属性,而 lateinit
只能应用于 var
s,因为不能编译成final
字段,不能保证不变性;
lateinit var
有一个存储值的支持字段,并且 bylazy { ... }
创建一个委托(delegate)对象,其中值存储一次计算后,将对委托(delegate)实例的引用存储在类对象中,并为与委托(delegate)实例一起工作的属性生成 getter。因此,如果您需要类中存在的支持字段,请使用 lateinit
;
除了 val
之外,lateinit
不能用于可空属性或 Java 原始类型(这是因为 null
用于未初始化的值);
lateinit var
可以从任何可以看到对象的地方初始化,例如从框架代码内部,单个类的不同对象可以有多个初始化场景。 bylazy { ... }
反过来定义了属性的唯一初始化程序,只能通过覆盖子类中的属性来更改它。如果您希望您的属性以一种事先可能未知的方式从外部初始化,请使用 lateinit
。
初始化 bylazy { ... }
默认是线程安全的,并保证初始化器最多被调用一次(但这可以通过使用 another lazy
overload 来改变)。在 lateinit var
的情况下,在多线程环境中正确初始化属性取决于用户的代码。
Lazy
实例可以被保存、传递,甚至可以用于多个属性。相反,lateinit var
s 不存储任何额外的运行时状态(只有 null
字段中的未初始化值)。
如果您持有对 Lazy
实例的引用,isInitialized()
允许你检查它是否已经被初始化(你可以obtain such instance with reflection从一个委托(delegate)属性)。要检查一个lateinit属性是否已经初始化,可以use property::isInitialized
since Kotlin 1.2 .
通过lazy { ... } 传递给的lambda 可能会从使用它的上下文中捕获引用到它的closure 中。 .. 然后它将存储引用并仅在属性初始化后才释放它们。这可能会导致对象层次结构(例如 Android 事件)不会被释放太久(或者永远不会被释放,如果该属性仍然可以访问并且永远不会被访问),因此您应该小心在初始化程序 lambda 中使用的内容。
另外,问题中没有提到另一种方法:Delegates.notNull()
,适用于非空属性的延迟初始化,包括Java基本类型。
关于properties - 使用 "by lazy"与 "lateinit"进行属性初始化,我们在Stack Overflow上找到一个类似的问题:
https://stackoverflow.com/questions/36623177/
我在 init block 中初始化响应但是抛出异常:/为什么? lateinit var response: MutableLiveData> init { response.valu
我想知道如何在 C# 中使用 后期初始化的 类字段和 可为空引用类型 。 想象一下下面的类: public class PdfCreator { private PdfDoc doc; p
我正在尝试使用注释@MockBean 初始化(通过模拟)两个对象 它似乎只有在我调用方法 mock(className) 时才有效,但由于我想在多个方法上使用模拟类,我不想在我的测试方法中重复相同的代
使用数据绑定(bind)、ViewModel、LiveData ( MVVM )。 在我的布局中有一个表单可以添加员工详细信息。 布局:
使用 Retrofit2 和 rxjava2 未在 Recyclerview 中设置 Gson 可转换数据,然后通过其订阅给出错误: UninitializedPropertyAccessExcept
我的 Kotlin Activity 中有 lateinit 属性,这是它的简化版本: class CreateNewListOfQuestions : AppCompatActivity() {
我有一个自定义的线性布局类,当我想创建这个类的实例时,我收到以下错误: lateinit 属性尚未初始化 我正在使用最新版本的 butterknife 库。 以下是我的 Kotlin 类: class
以下两种方法有什么区别或没有区别: 1. private lateinit var binding: ResultProfileBinding override fun onCreate(savedI
所以我想要实现的是稍后在主函数中设置顶级变量,但我不想让它成为一个肯定会破坏 Extension 的 lateinit var可变功能。 例如,此代码不起作用,因为扩展变量不支持 lateinit 修
如果我有一个 lateinit 变量,我可以检查它是否使用 (this::lateInitVar.isInitialized) 初始化,如 https://stackoverflow.com/a/47
关于这个问题已经有几个 QA,但对我来说,他们似乎在谈论不同的事情(大多数情况下是 Android 的 Kotlin + Dagger2),而不是应用我的具体案例。 我通过阅读 this blog p
成员 lateinit 变量初始化可以通过以下方式检查: class MyClass { lateinit var foo: Any ... fun doSomething()
以下 Kotlin 代码有效 val (x, y) = getSomeXYPair() 但是你不能用 lateinit 全局变量来做到这一点 class Foo { private latei
当我运行从 Firebase github 存储库下载的 quickstart-Android Firebase 数据库入门应用程序时,无论我选择(通过对话框)运行 Java 版本还是 Kotlin
您好,当我使用 Kotlin 编写 Android 程序时,我在代码中看到了 lateinit。 Java 中的等价物是什么?如何将此代码从 Kotlin 更改为 Java? public class
我想知道是否有办法检查 lateinit 变量是否已初始化。例如: class Foo() { private lateinit var myFile: File fun bar(pa
我是 Android 的新手,我正在尝试使用 Dagger2 和 MVVM 模式以及 kotlin 创建一个应用程序,但我无法让它运行。 我的应用类代码。 class PruebaDaggerApp:
我在 BreakingNewsFragment 中使用这一行 viewModel = (activity as NewsActivity).viewModel 初始化了 viewModel,但是收到以
我知道有类似的问题,但我只是找不到类似的东西,我一直在学习新的东西来学习,同时将 kotlin 合成转换为 viewvbinding模式,我遇到了这个错误 kotlin.UninitializedPr
我在尝试将环境变量值分配给 lateinit 变量时遇到错误。错误是“原始类型的属性不允许'lateinit'修饰符”。 我的application.properties(读取环境变量) my.pro
我是一名优秀的程序员,十分优秀!