Java 从构造函数调用方法

Java 从构造函数调用方法,java,class,constructor,Java,Class,Constructor,请原谅任何小的语法错误或诸如此类的错误,我在使用Jitsi模块时遇到了这种情况,并且对Java不是非常熟悉。我想确认发生了什么,为什么以及如何修复它 public abstract class A { public A() { this.load(); } protected void load() { } } public class B extends A { private String testString = null; public

请原谅任何小的语法错误或诸如此类的错误,我在使用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()
  • 初始化变量(根据调试器调用“private string testString=null”),将其置零
这是预期的Java行为吗?这是什么原因造成的?它是一个运行在1.7JDK上的Java1.6应用程序

这是预期的Java行为吗

这是什么原因造成的

在非最终超类构造函数中调用非最终重写方法

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

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

寓意:永远不要在构造函数中调用非final类的非final公共方法。

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

不需要为“null”赋值,可以将其删除

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

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

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;
    }
}

太棒了,谢谢。我将研究项目的其他部分是如何运行的,它们必须正确地运行,这是异常值,因此我将遵循应用程序的其余行为。这是否意味着如果我们从构造函数调用实例方法,我们调用的是一个半熟的对象的方法?load()是一种模块通常用于从.properties文件中提取配置的方法,我已经接触了Jitsi dev邮件列表,我们将了解他们对此的建议方法,以保持其代码的一致性(不是所有模块都加载属性,而且我已经厌倦了查看…无论如何都必须在其列表中提交错误)。好的,所以这不是道的东西。这将使它变得更简单——应该只是一个初始化路径
initAfterCreate()
是唯一基本可靠的解决方案,最好用静态工厂方法包装。为什么要投否决票?分享许多init在构建混乱方面的实际经验——它们出现的实际情况,以及解决这些问题的有效模式(“静态构造函数”)。