Подтвердить что ты не робот

Вызов метода из конструктора

Извините за любые незначительные синтаксические ошибки или что-то еще, я испытываю это с помощью модуля 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 с использованием класса нагрузки по методу name:

  • Вызывает переопределенную нагрузку() в классе B
  • Инициализирует переменные (вызывает "private string testString = null" в соответствии с отладчиком), обнуляя их.

Является ли это ожидаемым поведением Java? Что может быть причиной этого? Это приложение Java 1.6, работающее на 1,7 JDK.

4b9b3361

Ответ 1

Является ли это ожидаемым поведением Java?

Да.

Что может быть причиной этого?

Вызов неконфигурированного переопределенного метода в конструкторе внеклассного суперкласса.

Посмотрите, что происходит шаг за шагом:

  • Создается экземпляр B.
  • B() вызывает конструктор суперкласса - A(), чтобы инициализировать члены суперкласса.
  • A() теперь вызывает не конечный метод, который переопределяется в классе B, как часть инициализации.
  • Поскольку экземпляр в контексте имеет класс B, вызываемый метод load() имеет класс B.
  • load() инициализирует поле экземпляра класса B - testString.
  • Конструктор суперкласса завершает работу и возвращает (предположив, что цепочка конструктора до класса Object завершена)
  • Конструктор B() начинает выполнение, инициализируя его собственный член.
  • Теперь, в рамках процесса инициализации, B перезаписывает предыдущее записанное значение в testString и повторно инициализирует его до null.

Мораль: никогда не вызывать неконкурентный публичный метод не конечного класса в нем конструктор.

Ответ 2

Это общий шаблон проблемы с инициализацией на этапе строительства и часто можно найти в коде инфраструктуры и самодельных DAO.

Назначение "null" не требуется и может быть удалено.

Если этого недостаточно, как быстрый патч, то: Переместите все post-construction init в отдельный метод и оберните все это в псевдо-конструктор "статический метод".

И если вы делаете вещи DAO, очень хорошо различать "load" и "create", поскольку это совершенно разные экземпляры. Определите отдельные методы "статического конструктора" и, возможно, отдельные внутренние элементы для них.

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

Демонстрация разделения load/create для 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;
    }
}