在科特林如果你不想初始化构造函数中或在类主体的顶部的类属性,你已经基本上这两个选项(从语言参考):
- 延迟初始化
懒惰()是一个函数,它接受一个lambda,并返回懒惰的实例,它可以用作实现一个懒惰的财产委托:第一调用get()执行()传递给懒惰的Lambda和记忆的结果,后续调用获得()只是返回想起结果。
例
public class Hello { val myLazyString: String by lazy { "Hello" } }
所以第一个呼叫和呼叫subquential,无论它是,到myLazyString将返回“你好”
- 晚初始化
通常情况下,属性声明为具有一个非空的类型必须在构造函数被初始化。 然而,相当频繁,这是不方便。 例如,属性可以被初始化通过依赖注入,或在单元测试的设置方法。 在这种情况下,你不能在构造函数中提供一个非空的初始化,但你还是想引用类的体内的属性时,避免无效检查。
为了处理这种情况下,你可以标记与lateinit修改属性:
public class MyTest { lateinit var subject: TestSubject @SetUp fun setup() { subject = TestSubject() } @Test fun test() { subject.method() } }
所述改性剂可以仅在一个类(不是在主构造)的主体内声明变种特性被使用,并且仅当属性不具有自定义getter或setter。 该属性的类型必须是非空,它不能是原始类型。
那么,如何正确这两个选项之间进行选择,因为他们都可以解决同样的问题?
这里有之间的差异显著lateinit var
和by lazy { ... }
委托财产:
lazy { ... }
委托可以仅用于val
特性,而lateinit
只能应用于var
S,因为它不能被编译为一个final
字段,因此没有不变性可以得到保证;
lateinit var
具有存储所述值的支持字段,并且by lazy { ... }
创建在其中存储一次计算出的值的委托对象,存储所述参考类对象的代表实例,并生成用于吸气剂的性能该作品与委托实例。 所以,如果你需要存在于类支持字段,使用lateinit
;
除了val
S, lateinit
不能被用于为空的属性和Java基本类型(这是因为null
用于未初始化的值);
lateinit var
可以从任何地方的对象被认为是由例如从一个框架内的代码进行初始化,并且多个初始化场景是可能的用于单个类的不同的对象。 by lazy { ... }
反过来,定义了属性,这只能通过在子类中重写属性被改变的唯一初始化。 如果你希望你的财产从外面大概在未知的方式预先初始化,使用lateinit
。
初始化by lazy { ... }
是线程安全的默认设置,保证了初始调用最多一次(但可以通过改变另一个lazy
过载 )。 在的情况下lateinit var
,它是由用户的代码在多线程环境中正常初始化属性。
一个Lazy
实例可以被保存,通过周围,甚至用于多个属性。 相反地, lateinit var
■不要存储任何额外的运行状态(只有null
在未初始化值的字段)。
如果你坚持的一个实例的引用Lazy
, isInitialized()
允许你检查它是否已经被初始化(你可以得到这样的实例与反思从委托财产)。 要检查lateinit属性是否已经初始化,您可以使用property::isInitialized
因为科特林1.2 。
一个lambda传递给by lazy { ... }
它被使用到它可以捕捉从上下文引用关闭 ..然后它将存储引用和释放他们只有一次的财产已被初始化。 这可能会导致对象层次,比如Android的活动,而不是被释放时间过长(或曾经,如果物业仍然可以访问,并且永远不会访问),所以你应该小心你使用什么初始化拉姆达内。
此外,还有在这个问题没有提及另一种方式: Delegates.notNull()
它适用于非空性质的递延初始化,包括Java基本类型。
Additionnally到hotkey
的很好的答案,这里是我的两个实践中如何选择:
lateinit
是外部初始化:当你需要外部的东西通过调用一个方法来初始化自己的价值。
例如,通过调用:
private lateinit var value: MyClass
fun init(externalProperties: Any) {
value = somethingThatDependsOn(externalProperties)
}
虽然lazy
是当它仅使用依赖内部到对象。
非常简短的回答
lateinit:它最近初始化非空属性
不同于延迟初始化,lateinit允许编译认识到非空属性的值不存储在构造阶段正常编译。
延迟初始化
通过懒惰实施只读 (VAL),在执行科特林懒惰初始化属性时可能是非常有用的。
通过懒{...}执行其初始化,其中首先使用该定义的属性,而不是它的声明。
除了所有伟大的答案中,有一个叫做延迟加载的概念:
迟缓装载在计算机编程常用推迟对象的初始化,直到它被需要的点的设计模式。
使用得当,可以减少你的应用程序的加载时间。 而且它科特林方式的实现是lazy()
每当它的需要,它加载所需的价值,你的变量。
但是,当你确定一个变量不会为空或空的,你在使用它之前-例如,将被初始化lateinit使用onResume()
方法android-,所以你不希望将其声明为可空类型。
幸得@Amit谢卡尔
晚INIT
lateinit迟到初始化。
通常情况下,属性声明为具有一个非空的类型必须在构造函数被初始化。 然而,相当频繁,这是不方便。 例如,属性可以被初始化通过依赖注入,或在单元测试的设置方法。 在这种情况下,你不能在构造函数中提供一个非空的初始化,但你还是想引用类的体内的属性时,避免无效检查。
例:
public class Test {
lateinit var mock: Mock
@SetUp fun setup() {
mock = Mock()
}
@Test fun test() {
mock.do()
}
}
懒
懒是懒初始化。
lazy()
是一个函数,它接受一个lambda,并返回懒惰的实例,它可以用作实现一个懒惰的财产委托:第一次调用get()
执行传递到拉姆达lazy()
并记住结果,后续调用到get()
简单地返回想起结果。
例:
public class Example{
val name: String by lazy { “Amit Shekhar” }
}
如果你正在使用Spring容器,并要初始化非空的豆场, lateinit
更适合。
@Autowired
lateinit var myBean: MyBean
一个实例lateinit
(什么是迟到的初始化):
public class Late {
lateinit var mercedes: Mercedes
@SetUp fun setup() {
mercedes = Mercedes()
}
@Test fun testing() {
mercedes.do()
}
}
一个实例lazy
(什么是懒初始化):
public class Lazy {
val name: String by lazy { "Mercedes-Benz" }
}
文章来源: Kotlin - Property initialization using “by lazy” vs. “lateinit”