Java - почему он печатает ноль? - PullRequest
5 голосов
/ 06 сентября 2011
public class Base {
public Base() {
    x = 0;
    bar();
}

public Base(int x) {
    this.x = x;
    foo();
}

public void foo() {
    System.out.println("Base.foo : " + x);
}

private void bar() {
    System.out.println("Base.bar:" + x.toString());
}

protected Integer x;
}

    public class Derived extends Base {
       public Derived() {
       bar();
       }
       public Derived(int x, int y) {
         super(x);
         this.y = y;
       }
       public void foo() {
         System.out.println("Derived.foo : " + x + ", " + y);
       }
       public void bar() {
         System.out.println("Derived.bar:" + x.toString() + ", " + y.toString());
       }
       private Integer y;


       public static void main(String[] args) {
        Base b = new Derived(10, 20);
      }
}

Почему печатается "Derived.foo:" 10, nulll, а не 20 вместо нуля?у является частной переменной Derived, и она была инициализирована с 20. она находится в своей области видимости .. так почему же это ноль?

Ответы [ 8 ]

7 голосов
/ 06 сентября 2011

Потому что сначала вызывается супер-конструктор (super(x)).Этот супер-конструктор вызывает метод foo.Затем конструктор Derived инициализирует y значением 20 (this.y = y).Поэтому, когда вызывается foo, y еще не инициализирован.

Это плохая практика вызывать переопределенные методы в конструкторах, потому что, как вы только что заметили, он может вызывать переопределенные методы для частично построенных объектов.

2 голосов
/ 06 сентября 2011

Если вы следите за вызовами конструктора, это делает его более понятным:

  1. Вызывает конструктор Derived(int x, int y)
  2. Вызывает суперконструктор Base(int x)
  3. Устанавливает x переменную
  4. Вызывает переопределенный foo() метод
  5. Выполняет println()
  6. Затем устанавливаетпеременная y

Как видите, переменная y устанавливается после того, как вы попытаетесь распечатать значение.Вот почему вы видите неинициализированное значение null.

Вызов переопределенных методов из конструктора является распространенной ошибкой, поскольку он может позволить неинициализированным переменным завершиться до того, как объект будет полностью построен.

2 голосов
/ 06 сентября 2011

Это происходит потому, что конструктор суперкласса (Base) вызывает Derived.foo() до того, как была установлена ​​переменная-член y.

Итак, вот основной порядок операций:

main(...)
Derived(10,20) (start constructor)
Base(10) (start constructor)
this.x = x
foo() (calls Derived.foo() which prints the message you see)

Затем после этого

this.y = y
2 голосов
/ 06 сентября 2011

println происходит от метода foo, который вызывается из конструктора Base, который вызывается из конструктора Derived (через super) до , который вы инициализируете y. Так что ожидается нулевое значение.

1 голос
/ 06 сентября 2011

потому что y не был инициализирован при вызове foo () в конструкторе базового класса.

цепочка становится главной -> Derived (x, y) -> Base (x) -> инициализировать x,Foo ().Однако, поскольку вы начинаете вызов внутри Derived, который переопределяет foo (), производная функция foo () фактически выполняется интерпретатором.

1 голос
/ 06 сентября 2011

Все ответы действительно верны, но в следующий раз вы можете поставить точку останова в функции, где вы печатаете что-то.Затем вы можете просто проверить стек вызовов и следовать коду, читая вызываемые части.

Таким образом, вы могли бы проследить, что y не будет инициализирован.Рул

1 голос
/ 06 сентября 2011

Он печатается с помощью Derived.foo(), вызванного вызовом Super-Constructor, до того, как он будет инициализирован с 20 впоследствии.Таким образом, во время печати он все еще нулевой.

1 голос
/ 06 сентября 2011

Когда вы попадаете в конструктор суперкласса, y еще не создан.Таким образом, вызов foo() будет иметь null y.

...