在构造函数(注意:init 块和给成员变量(属性)赋初值的语句,都是构造函数的一部分)中使用 this 时,可能会出现这个警告。如果不理会,可能导致访问到未初始化的成员变量。Java 中,它们可以是未赋初值或赋值为 null 的引用类型;Kotlin 中,可以是 lateinit var 或未赋值或赋值为 null 的可空类型。
事实上,在构造函数中使用 this,即便这个类是 final 的(Kotlin 中则为没有 open 修饰的类),也有可能导致这样的后果。这主要发生在将 this 作为参数(实参)传递给其它函数,或者添加到 Array 之类的情形中。在这些条件下,其它函数可以通过这个引用访问到该类的公有成员。然而,在使用 this 这一行的语句之后,可以还有其它语句;又或者,这条语句是调用了其它函数,在这个被调用的函数里完成了传递 this 引用或将其添加到数组之类的动作。很显然,这一瞬间,构造函数还没有执行完毕(没有返回)。在多线程的条件下,如果其它函数可以使用 this 引用(比如,在添加到 ArrayList 后,就立即通过条件变量的 notify 操作通知其它线程,这些线程继续执行的时候,通过这个引用,访问该类的实例),那么,它们就有可能在该类的实例的构造函数未完成的时候,访问到尚未被初始化的成员,进而 NullPointerException。此外,并不是在构造函数的最后一条语句里才这么做就万事大吉。为了提升性能,语句(指令)的顺序是可以被重排的。也就是说,在函数本体中,最后才出现的语句不一定是最后才被执行的。
如果这个类还有子类,更有可能出现这样的后果。通常,会在子类的构造函数中调用父类的构造函数。父类的构造函数将 this 暴露给其它函数的时候,子类还没有构造完毕。其它函数可以通过这个 this 引用,访问到子类的成员。而这些成员里,自然有可能存在一些尚未初始化的成员。
当然,毕竟这只是一个警告。如果置之不理,还是能通过编译的。假使实在需要这样做,也并不是不行。不过,如果产生了 NullPointerException,且异常点所在的类存在子类,或程序是多线程的;并且涉及的这些类的代码中存在这样的警告,则可以考虑往这个方面排查原因。