在 Kotlin 中,如果您有一个在其构造函数或块中open引用的类,您(非常正确)会收到编译器警告:thisinit
在非最终类的构造函数中泄漏“this”
原因在此处解释。
我的问题是:为什么在班级结束时不报告这一点?如果this在该init块完成之前在该块中使用,则该对象仍未处于完全构造状态,所以警告不应该也适用于那里吗?
这甚至可能导致val属性似乎在运行时发生变化的情况。以这段代码为例:
class Listener {
fun onCreated(leaker: Leaker) = println("Listener hears that leaker created with a value of ${leaker.myVal}")
}
class Leaker(listener: Listener) {
val myVal: Int
init {
listener.onCreated(this)
myVal = 1
println("Leaker knows that it's been created with a value of $myVal")
}
}
Run Code Online (Sandbox Code Playgroud)
使用这些对象如下:
Leaker(Listener())
Run Code Online (Sandbox Code Playgroud)
将导致以下输出:
Listener hears that leaker created with a value of 0
Leaker knows that it's been created with a value of 1
Run Code Online (Sandbox Code Playgroud)
请注意,myVal最初报告为 0,然后为 1。
可以看出,Leaker将自身的实例传递给ListenerbeforeLeaker已完全构造。Listener然后可以在myVal初始化之前访问该属性,因此它将具有默认值(在这种情况下为 0,因为它是一个整数)。稍后Listener更改此属性的值(在本例中为 1)。这意味着程序的行为就像 aval发生了变化。
编译器应该警告你吗?
Rol*_*and 15
tl;博士: https : //youtrack.jetbrains.com/issue/KT-22044非常适合解决这个问题。
我将引用 Intellij IDEAs 检查中称为“在构造函数中泄漏‘这个’”的内容:
该检查报告了构造器内部的危险操作,包括:
- 在构造函数中访问非最终属性
- 在构造函数中调用非最终函数
- 在非最终类的构造函数中使用this作为函数参数
这些操作很危险,因为您的类可以被继承,而此时派生类尚未初始化。典型例子:
Run Code Online (Sandbox Code Playgroud)abstract class Base { val code = calculate() abstract fun calculate(): Int } class Derived(private val x: Int) : Base() { override fun calculate() = x } fun testIt() { println(Derived(42).code) // Expected: 42, actual: 0 }
我认为仍然应该有警告,因为您可以访问未初始化的变量。原因:编译器已经禁止直接访问未初始化的变量,即以下不会编译:
class Demo {
val some : Int
init {
println(some) // Variable 'some' must be initialized
Run Code Online (Sandbox Code Playgroud)
但是间接访问它会编译并显示变量类型的默认值:
class Demo2 {
val some : Int
val someString : String
init {
fun Demo2.indirectSome() = some
fun Demo2.indirectSomeString() = someString
println(indirectSome()) // prints 0
println(indirectSomeString()) // prints null; and yes.. this can lead to NullPointerExceptions
Run Code Online (Sandbox Code Playgroud)
在那里我们也有一个“泄漏”,基本上是some在它应该之前访问;-)
| 归档时间: |
|
| 查看次数: |
9526 次 |
| 最近记录: |