为什么我在使用No.2脚本时Android Studio会显示错误。
我发现1和2之间没有区别。

class Adapter {
    var nameList : ArrayList<String>? = null
}

class Program {
    private fun send() {
        val list: ArrayList<String> = ArrayList()
        val adapter = Adapter()

// Case 1
        var otherList = adapter.nameList
        if (otherList != null) {
            list.addAll(otherList) // <--- no error
        }

// Case 2
        if (adapter.nameList!=null) {
            list.addAll(adapter.nameList) // <--- Error here
            // Smart cast to 'kotlin.collections.ArrayList<String> /* = java.util.ArrayList<String> */' is impossible, because 'adapter.nameList' is a mutable property that could have been changed by this time
        }
    }
}

请说明这种情况

最佳答案

IDE应该向您发出警告,解释说在执行空检查之后,很可能另一个线程已更改了adapter.nameList,并且当您调用list.addAll(adapter.nameList)时,到那时adapter.nameList实际上可能为空(再次,因为另一个线程可能已更改值。这将是竞争条件)。

您有一些解决方案:

  • nameList设为val,使其成为final。由于它是最终的,因此可以保证另一个线程无法更改它。这可能不适合您的用例。
    class Adapter {
        val nameList : ArrayList<String>? = null
    }
    
  • 在执行检查之前,请创建名称列表的本地副本。因为它是本地副本,所以编译器知道另一个线程无法访问它,因此无法对其进行更改。在这种情况下,可以使用varval定义本地副本,但我建议使用val
    val nameList = adapter.nameList
    if (nameList != null) {
        list.addAll(nameList)
    }
    
  • 在这种情况下,请使用Kotlin提供的实用程序功能之一。 let函数使用内联函数将其调用的引用复制为参数。这意味着它可以有效地编译为与#2相同的代码,但是更加简洁。 我更喜欢这种解决方案。
    adapter.nameList?.let { list.addAll(it) }
    
  • 10-08 03:45