当前位置: 首页 > 知识库问答 >
问题:

使用“by lazy”与“lateInit”初始化属性

龚浩宕
2023-03-14
  1. 惰性初始化

lazy()是一个接受lambda并返回lazy 实例的函数,该实例可以作为实现lazy属性的委托:对get()的第一次调用执行传递给lazy()的lambda并记住结果,随后对get()的调用只返回记住的结果。

public class Hello {

   val myLazyString: String by lazy { "Hello" }

}
public class MyTest {
   
   lateinit var subject: TestSubject

   @SetUp fun setup() { subject = TestSubject() }

   @Test fun test() { subject.method() }
}

修饰符只能用于在类主体中声明的var属性(而不是在主构造函数中),并且只能在属性没有自定义getter或setter时使用。属性的类型必须是非空的,并且不能是基元类型。

那么,既然这两个选项都能解决同样的问题,如何在这两个选项之间做出正确的选择呢?

共有1个答案

冯良才
2023-03-14

以下是lateinit varby lazy{...}委托属性之间的显著差异:

>

  • lazy{...}委托只能用于val属性,而lateinit只能应用于vars,因为它不能编译为final字段,因此不能保证不变性;

    LateInit var有一个用于存储值的支持字段,而by lazy{...}创建一个委托对象,在计算完后将值存储在其中,在类对象中存储对委托实例的引用,并为与委托实例一起工作的属性生成getter。因此,如果需要类中存在支持字段,请使用lateInit

    除了vals之外,lateinit不能用于可为空的属性或Java基元类型(这是因为null用于未初始化的值);

    LateInit var可以从任何可以看到对象的地方初始化,例如从框架代码内部初始化,对于单个类的不同对象可以使用多种初始化方案。by lazy{...}反过来为属性定义了唯一的初始值设定项,只能通过在子类中重写属性来更改该初始值设定项。如果希望从外部以事先可能未知的方式初始化属性,请使用lateInit

    默认情况下,由lazy{...}初始化是线程安全的,并保证最多调用一次初始化程序(但可以通过使用另一个lazy重载来改变这一点)。对于LateInit var,在多线程环境中正确初始化属性取决于用户的代码。

    如果您持有对lazy实例的引用,isinitialized()允许您检查它是否已经初始化(您可以从委托属性中通过反射获得这样的实例)。要检查lateinit属性是否已经初始化,可以使用property::IsInitialized,因为Kotlin1.2。

    由lazy{...}传递给的lambda可能会从其闭包中使用的上下文捕获引用。然后,它将存储引用,并仅在属性初始化后释放它们。这可能会导致对象层次结构(如Android activities)太长时间没有发布(或者,如果属性保持可访问且从未被访问),所以您应该小心在初始化器lambda中使用什么。

    另外,还有一种方法在问题中没有提到:delegates.notnull(),它适合于延迟初始化非空属性,包括Java基元类型的属性。

  •  类似资料:
    • 我不知道这是怎么回事 主要活动 我遇到了这个问题 2022-03-18 09:18:27.393 13874-13874/com。实例githubuser2 E/AndroidRuntime:致命异常:主进程:com。实例githubuser2,PID:13874 java。lang.RuntimeException:无法启动活动组件信息{com.example.githubuser2/com.e

    • 我正在尝试使用Spring-boot+Vaadin创建一个web项目,并且希望使用spring-data-jpa和hibernate从PostgreSQL数据库中获取数据。 在我的Vaadin看来,我尝试自动连接我的服务类,但我总是得到null,而且eror堆栈跟踪没有告诉我原因。 数据库得我得配置: 视图和UI: pom.xml: 我的服务: 更新的解决方案:

    • 我正在为DI与Dagger2的项目工作。我正在MVP架构中注入presenter。由于某种原因,当我构建应用程序时,它会出现错误:“LateInit property presenter has not been initialized”。我知道这意味着没有注射,但我不明白为什么。下面是我的代码: 应用程序类 家庭模块 AppComponent 房屋结构 如果需要任何关于代码的其他信息,请询问..

    • 当变量只在OnCreate中声明时,为什么我的片段不进入onCreateView?

    • 我的代码成功构建,但每当我运行它时都会出现异常。不知道为什么匕首2不初始化变量。请告诉我哪里错了。给出以下例外情况: UninitializedPropertyAccessException:lateinit属性databaseService尚未初始化 依赖关系:

    • 我经常得到。但这个应用程序运行得很好。注意:我不想将演示者注入到活动中。提前谢谢! 以下是我的活动: 这是我的主持人: 这是我的数据管理器: 和AppDataManager: 最后,我的测试失败了: gradle文件: 我的模块课程: 实际错误是科特林。UninitializedPropertyAccessException:lateinit属性dataManager尚未初始化