什么是“this-escape”警告,我该如何处理它?

dav*_*hew 1 java warnings scope compiler-warnings this-pointer

我很难找到这方面的资源,但是,当我在最新的 Java (21) 上编译代码时,我的很多类都遇到了这个错误。

这是一个代码示例。

public class ThisEscapeExample
{

        public Object o;

        public ThisEscapeExample()
        {

                this.overridableMethod();

        }

        public void overridableMethod()
        {

                this.o = new Object();

        }

}
Run Code Online (Sandbox Code Playgroud)

这是我的编译命令。

javac -Xlint:all ThisEscapeExample.java
ThisEscapeExample.java:9: warning: [this-escape] possible 'this' escape before subclass is fully initialized
                this.overridableMethod();
                                      ^
1 warning
Run Code Online (Sandbox Code Playgroud)

dav*_*hew 6

这是引入此新警告的 JDK Bug 系统条目 - https://bugs.openjdk.org/browse/JDK-8299995

长话短说,该this-escape警告是在子类可以@Override使用超类构造函数中也调用的方法时向您发出警告。

这是危险的,因为重写构造函数中使用的方法会导致子类在子类初始化期间无意中引入错误。如果该方法依赖于尚未创建的状态,因为我们仍在超级构造函数中怎么办?毕竟,在调用超级构造函数之前(目前),您不能在子类的构造函数中执行任何操作。

有几种方法可以解决这个问题。

  1. 仅使用构造函数中不能被重写的方法。

    • static方法。

    • final方法。

    • private方法。

  2. 自己制作课程final

  3. 不要传入/使用this开头 - 相反,传入this您需要的特定组件。

    • 基本上,不要再偷懒了,明确你的需求。不要只传递你的God 对象——只传递你需要的特定属性。

请注意 - 这些规则递归适用。这意味着,当您在构造函数中调用方法时,不仅该方法必须是“不可重写的”,而且该方法传递到的方法this必须匹配上述规则之一。如果您的顶级方法不可重写,但其中的方法之一是可重写的,并且该方法在其范围内,那么您将在编译时收到错误。这是一个例子。thisthis-escape

import javax.swing.*;

public class GUI
{

   private final JFrame frame;

   public GUI()
   {
   
      this.frame = new JFrame();
   
      this.frame.add(this.createBottomPanel());
   
   }

   //final! Does that mean we are safe?
   final JPanel createBottomPanel()
   {
   
      final JButton save = new JButton();
   
      save
         .addActionListener
         (
            /*
             * No. We get the warning here at the start of this lambda.
             * The reason is because we have given this lambda the
             * ability to call this.toString(), and we don't know when
             * it will do that. Maybe now, maybe later. But if it does
             * it now, then we could end up doing things before the
             * object is fully created. And if that were to happen, then
             * that would be a this-escape. So, the warning occurs here,
             * to let you know that it is possible.
             */
            actionEvent ->
            {
           
               this.toString();
           
            }
           
         )
         ;
   
      return null;
   
   }

}
Run Code Online (Sandbox Code Playgroud)