Try English version of Quizful



Раздаем бесплатные Q! подробности в группе Quizful.Alpha-test
Партнеры
Рекрутерам: Прескрининг кандидатов about
Топ контрибуторов
loading
loading
Знаете ли Вы, что

Список полученных сертификатов находится на странице Вашего профиля. Сертификаты можно распечатать или разместить на Вашем сайте.

Лента обновлений
ссылка 20:57:36
Комментарий от Recrut_rf:
Спасибо, сохранил функцию, может пригодится когда - ни...
ссылка 20:53:59
Добавлен вопрос в тест ASP.NET - Основы
ссылка 08:41:09
Комментарий от Krosster:
Гарний сайт для новачків. Правда деякі питання підступн...
ссылка Apr 22 22:06
Добавлен вопрос в тест SQL - Средний уровень
ссылка Apr 22 10:13
Комментарий от Entrery:
вроде выбрал ООП в сишарпе, а тут вопросы по джаве...
Статистика

Тестов: 153, вопросов: 8596. Пройдено: 402470 / 1961087.

Инициализация полей в Java (Java fields initialization)

head tail Статья
категория
Java
дата17.06.2009
авторyohan
голосов79

Введение

Как известно, в Java поля (fields) могут принадлежать классу или объекту. Поля, принадлежащие классу, являются статическими, а поля, принадлежащие объекту, - нестатическими. Статические поля доступны без создания объекта класса. Соответственно инициализироваться статические и нестатические поля должны в разное время: одни до создания объекта класса, а другие после.

Типы инициализации полей объектов и классов

Существуют следующие методы инициализации полей:

Название Применимость Описание
Инициализация в месте объявления поля Поля класса, поля объекта Применяется, если инициализация может быть произведена коротким выражением и доступен контекст, необходимый для ее проведения
Инициализационный блок Поля класса, поля объекта Применяется, если инициализационный код неудобно записывать одним выражением или же, например, нужна обработка проверяемых исключений. В случае объектов может применяться для инициализации полей объектов анонимных классов.
Конструктор класса Поля объекта Применяется, если для инициализации нужны параметры конструктора

Далее мы рассмотрим каждый тип инициализации подробнее.

Инициализация статических полей в месте объявления

Начнем с примера:


class Integer {
    ...
    public static final int SIZE = 32;
    ...
}

Здесь инициализируется статическое поле SIZE класса Integer. Сама инициализация произойдет во время загрузки класса. В этом легко убедиться выполнив следующий код:


public class StaticInitializationTime {
    public static class C {
        static int i = value();
        static int value() {
            System.out.println("C.i initialized");
            return 1;
        }
    }

    public static void main(String[] args) throws ClassNotFoundException {
        System.out.println("Before class loading");
        Class.forName(C.class.getName());
        System.out.println("After class loading");
    }
}

В результате будет выведено:


Before class loading
C.i initialized
After class loading

Как видно из вывода переменная i инициализируется в результате загрузки класса. Попробуйте выполнить код, закомментировав строку, содержащую Class.forName(...).

Инициализация в статическом блоке

В некоторых случаях инициализацию неудобно проводить в месте объявления переменной. Например, если в результате выполнения инициализирующего выражения происходит проверяемое исключение. Или же, если инициализация производится путем выполнения кода, который не может быть представлен в виде выражения. Для таких случаев в Java предусмотрен специальный языковой элемент - инициализационный статический блок. Покажем на примере:


static List<Character> alphabet;
static {
    alphabet = new ArrayList<Character>();
    for (char c='a'; c<='z'; c++) alphabet.add(c);
}

Переменная alphabet инициализируется в статическом блоке. Инициализация происходит во время загрузки класса аналогично как и в предыдущем примере.

Инициализация статических полей в месте объявления и статические блоки выполняются в порядке их объявления в классе. Давайте выполним следующий код:


public class ClassFieldsInitOrder {
    static int i1 = initialize("i0");

    static int i2;
    static { i2 = initialize("i1"); }

    static int i3 = initialize("i2");

    static int i4;
    static { i4 = initialize("i4"); }

    static int initialize(String name) {
        System.out.println(name);
        return 0;
    }

    public static void main(String[] args) {}
}

На консоль будет выведено:


i0
i1
i2
i4

Инициализация полей объекта

В отличии от полей класса, поля объекта инициализируются во время конструирования экземпляра класса. В Java существует 3 типа такой инициализации:

  • инициализация в месте объявления
  • инициализация в нестатическом блоке
  • инициализация в конструкторе

Инициализация полей объекта в месте объявления

Покажем на примере:


public class Blog {
    ...
    private List<Post> posts = new ArrayList<Post>
    ...
}

Инициализация поля posts будет произведена во время конструирования объекта Blog.

Инициализация полей объекта в нестатическом блоке

Использование инициализационных блоков является альтернативой предыдущему способу инициализации. Данный тип инициализации может использоваться, если:

  • во время инициализации необходимо обработать проверяемое исключение
  • значение поля не удобно вычислять с помощью выражения (например, для этого нужен специально созданный класс или метод, который не хочется создавать только для этих целей)
  • необходимо инициализировать поле анонимного класса (в анонимном классе невозможно объявить конструктор)

Пример обработки проверяемого исключения:


class Year2000Problem {
    Date start;
    {
        try { start = new SimpleDateFormat("dd.MM.yyyy").parse("01.01.2000"); }
        catch (ParseException impossible) {}
    }
}

Инициализация полей объекта в конструкторе

Часто инициализацию полей объекта имеет смысл проводить только с учетом значений параметров конструктора. В таких случаях ее производят в самом конструкторе. Пример:


class User {
    ...
    String login;

    User(String login) { this.login = login; }
    ...
}

Инициализация в конструкторе и наследование

Выполним следующий код:


public class InheritanceInitOrder {
    static class A {
        String a;
        A() {
            a = "a";
            System.out.println("a initialized");
            System.out.println("b=" + ((B)this).b);
        }
    }

    static class B extends A {
        String b;
        B() {
            b = "b";
            System.out.println("b initialized");
            System.out.println("b=" + b);
        }
    }

    public static void main(String[] args) throws ClassNotFoundException {
        new B();
    }
}

В out будет выведено:


a initialized
b=null
b initialized
b=b

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

  • конструктор B первым делом вызвал конструктор предка - класса A
  • конструктор A проинициализировал поле a объекта А
  • при возврате из конструктора A, конструктор B проинициализировал поле b объекта B

Порядок инициализации полей объекта

Давайте теперь проанализируем порядок выполнения инициализаторов полей объекта. Для этого выполним код, включающий все типы инициализаторов:


public class ObjectFieldsInitOrder {
    static int initialize(String message) {
        System.out.println(message);
        return 0;
    }

    static class A {
        int i0 = initialize("i0");

        int i1;
        { i1 = initialize("i1"); }

        int i2 = initialize("i2");

        int i3;
        A() { i3 = initialize("i3"); }
    }

    static class B extends A {
        int i4 = initialize("i4");

        int i5;
        { i5 = initialize("i5"); }

        int i6;
        B() { i6 = initialize("i6"); }
    }

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

В результате выполнения получим:


i0
i1
i2
i3
i4
i5
i6

Вывод свидельствует о том что:

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

Результат декомипляции предыдущего примера

Ну и напоследок давайте декомпилируем следующий код с помощью Jad:


public class InitOrder4Jad {
    static int i0 = 1;

    static int i1;
    static { for (int i=0; i<10; i++) i1=i; }

    int i2 = 1;

    int i3;
    { i3 = 1; }

    int i4;
    InitOrder4Jad() { i4 = 1; }
}

Получился следующий листинг:


public class InitOrder4Jad
{

    InitOrder4Jad()
    {
        i2 = 1;
        i3 = 1;
        i4 = 1;
    }

    static int i0 = 1;
    static int i1;
    int i2;
    int i3;
    int i4;

    static
    {
        for(int i = 0; i < 10; i++)
            i1 = i;

    }
}

Интересно, что компилятор перенес всю нестатическую инициализацию объекта в конструктор класса. При этом статический инициализационный блок остался без изменений.

Выводы

Java предоставляет богатый арсенал языковых инструментов. Какие из них когда использовать - решать разработчику. Но важно знать о наличии их всех и важно отчетливо понимать, почему выбран тот или иной в каждом конкретном случае.

--
Желаю удачи!
Дмитрий Пекар, июнь 2009

Если Вам понравилась статья, проголосуйте за нее

Голосов: 79  loading...
admin   c0nst   morty   bwf   patisonka   alexis112   ilia   MaxT   vrungel   olextech   lightstorm   unforgiven250   Icem   hkvd   uniservise   lifeisgoodmf   cars   ayscha   aprl_mary   ldkfa   alex_agency   helpa   art   underworld   dector   Saimon2k   milkomil   chuwak   Skrakan   hennickel   oleg_pr   shokko_rockko   vavisha   Kadavrius   verto   Shved90   hypocrite07   alejandromay   Lapenkov   bardakov   andrey_z91h   s9rj10   wolfvet   VooDi   DIA_Doca   Ilyukhina   Laplace   soundtrack   Gelerion   aldir   start321   dotoni   polinkot   yachmenev   Selfing   Grishman   dtsuran   SamTan   ukuelig   zubr13   robolitan1   iLynx   taras4uprynka   DmitryOrlik   rafMaestro   laz   nick_hammer   darbodya   CSharpToJava   zeen   fil7   sbfi   bal_gena   hardxx   PyrkhAnna   ellobo12   stasyan72   verde_cavallone   Genua