Xpoint
   [напомнить пароль]

Задачка! Порядок инициализации переменных объекта

Метки: [без меток]
[арх]
2007-03-07 15:36:35 [обр] 30-ый(59/584)[досье]

Только что угробил полдня на поиск ошибки!!!

Задача: Что будет выведено на экран?

public class Rrr {
   public static void main(String[] args) {
      new B();
   }
}

class B extends A {
   private final Integer i = new Integer(5);
   public B() {
      super();
   }
   public void init() {
      super.init();
      System.out.println(i);
   }   
}

class A {
   public A() {
      init();
   }
   public void init() {
   }
}
спустя 1 час 12 минут [обр] Владимир Хоменко(2/67)[досье]

Неожиданно, но логично (-;

Вот поэтому и советуют придерживаться правила:

Делайте в конструкторе настолько меньше, насколько можете и если это возможно, то не вызывайте никаких методов
спустя 18 минут [обр] GRAy(14/259)[досье]

null - ответ правда получен экспериментальным путём :).
Вот тоже забавный пример (изменил только класс B):

class B extends A {
   private final Integer i = new Integer(5);
   private final int ii = 2;
   public B() {
      super();
   }
   public void init() {
      System.out.println(" i = "+i);
      System.out.println(" ii = "+ii);
   }   
}

В таком варианте будет выведено:
i = null
ii = 2
Владимир Хоменко[досье] Если не трудно, поясните логику.

спустя 19 минут [обр] Владимир Хоменко(2/67)[досье]
Порядок инициализации:
  1. Место отведенное под объекты инициализировано в ноль (i=null).
  2. Вызывается конструктор класса A.
  3. Вызывается переопределенный метод init().
  4. Инициализируются элементы класса B.
  5. Вызывается тело конструктора B.
спустя 39 минут [обр] Владимир Хоменко(2/67)[досье]

Вот, порылся немного в документации, чтобы не быть голословным:

http://java.sun.com/docs/books....../html/execution.doc.html#44670

Unlike C++, the Java programming language does not specify altered rules for method dispatch during the creation of a new class instance. If methods are invoked that are overridden in subclasses in the object being initialized, then these overriding methods are used, even before the new object is completely initialized.
спустя 19 часов [обр] Даниэль Алиевский(35/125)[досье]

А я сразу понял, что null будет :)
То, что ii=2, а не 0, вероятно, связано со специальной обработкой final-констант: компилятор имеет право заменить их появления в тексте методов непосредственно на их значения. Для примитивных типов, вероятно, он так и делает. Мог бы и для Integer (ибо неизменяемый), так что, думаю, результат теста зависит от применяемого компилятора.

Подобная ошибка, кстати, периодически возникает у меня в реальных проектах. Только речь идет об инициализации классов, а не экземпляров - там подобные ситуации отследить сложнее. Упрощенно, примерно так:

public class A {
   static int CONST_1 = B.getIntProperty("const1");
   static String name = "ClassA";
   public static void main(String[] args) {
      System.out.println(CONST_1);
      System.out.println(B.getIntProperty("const1"));
   }
}
class B {
   public static int getIntProperty(String propertyName) {
       return Integer.getInteger(A.name + "." + propertyName, 12);
   }
}

Вызываем: "java -DClassA.const1=14 A"
Как думаете, чему равно CONST_1 :)

спустя 33 минуты [обр] 30-ый(59/584)[досье]
компилятор имеет право заменить их появления в тексте методов непосредственно на их значения. Для примитивных типов, вероятно, он так и делает
А для непримитивных он просто не имеет права так делать. Иначе может полная фигня получится.
спустя 23 часа [обр] Даниэль Алиевский(35/125)[досье]
30-ый[досье] Смотря для какого компилятора. Конечно, в Java нет спецификатора immutable, но компилятор имеет право последовать документации на классы из пакетов java.* и опознать, что тип данных Integer, скажем, неизменяемый. Соответственно, ведет себя так же предсказуемо, как и примитивный int. Все равно в современной Java wrapper-типы обрабатываются по-особому (autoboxing).
Powered by POEM™ Engine Copyright © 2002-2005