22

请原谅任何小的语法错误或诸如此类的东西,我正在使用 Jitsi 模块遇到这种情况,并且对 Java 不太熟悉,想确认发生了什么以及为什么以及如何修复它。

 public abstract class A
{
  public A()
  {
    this.load();
  }

  protected void load()
  {

  }
}

public class B extends A
{
  private String testString = null; 

  public B()
  {
    super();
  }

  @Override
  protected void load()
  {
    testString = "test";
  }
}

应用程序在使用按名称加载类的方法创建类 B 的实例时执行此操作:

  • 在 B 类中调用重写的 load()
  • 初始化变量(根据调试器调用“私有字符串 testString = null”),将它们清零。

这是预期的 Java 行为吗?什么可能导致这种情况?它是在 1.7 JDK 上运行的 Java 1.6 应用程序。

4

2 回答 2

59

这是预期的 Java 行为吗?

是的。

什么可能导致这种情况?

您在非最终超类构造函数中调用非最终覆盖方法。

让我们一步一步来看看会发生什么:

  • 您创建一个B.
  • B()调用超类构造函数 - A(),初始化超类成员。
  • A()现在调用一个在类中被覆盖的非最终方法B,作为初始化的一部分。
  • 由于上下文中的实例属于B类,因此load()调用的方法属于B类。
  • load()初始化B类实例字段 - testString
  • 超类构造函数完成工作并返回(假设构造函数链接直到Object类完成)
  • 构造B()函数开始进一步执行,初始化它自己的成员。
  • 现在,作为初始化过程的一部分,B覆盖之前写入的值testString,并将其重新初始化为null.

道德:永远不要在其构造函数中调用非最终类的非最终公共方法。

于 2013-08-09T00:31:55.233 回答
5

这是构造时初始化的常见问题模式,经常可以在基础设施代码和自制 DAO 中找到。

对“null”的分配是不需要的,可以删除。

如果这还不足以作为快速补丁,那么: 将所有后期构造 init 移动到一个单独的方法中,并将其全部包装在一个“静态方法”伪构造函数中。

如果你在做 DAO 的东西,区分“加载”和“创建”真的很好,因为它们是完全不同的实例化。为这些定义单独的“静态构造函数”方法和可能单独的内部初始化。

abstract public class A {
    protected void initAfterCreate() {}
}

public class B {

    @Override
    protected void initAfterCreate() {
        this.testString = "test";
    }

    // static constructors;
    //     --        
    static public B createB() {
        B result = new B();
        result.initAfterCreate();
    }
}

演示DAO 的加载/创建分离:

public class Order {
    protected int id;
    protected boolean dbExists;

    static public load (int id) {
        Order result = new Order( id, true);
        // populate from SQL query..
        return result;
    }
    static public create() {
        // allocate a key.
        int id = KeyAlloc.allocate( "Order");
        Order result = new Order( id, false);
    }

    // internal constructor;  not for external access.
    //
    protected Order (int id, boolean dbExists) {
        this.id = id;
        this.dbExists = dbExists;
    }
}
于 2013-08-09T00:45:11.997 回答