запрет на создание объектов этого класса, например, невозможно создать экземпляр класса Math ;
реализация специального шаблона проектирования из ООП Singleton, для работы которого требуется контролировать создание объектов, что невозможно в случае наличия не- private конструкторов.
Инициализаторы
Наконец, последней допустимой конструкцией в теле класса является объявление инициализаторов. Записываются объектные инициализаторы очень просто – внутри фигурных скобок.
public class Test { private int x, y, z; // инициализатор объекта { x=3; if (x>0) y=4; z=Math.max(x, y); } }
Инициализаторы не имеют имен, исполняются при создании объектов, не могут быть вызваны явно, не передаются по наследству (хотя, конечно, инициализаторы в родительском классе продолжают исполняться при создании объекта класса-наследника).
Было указано уже три вида инициализирующего кода в классах – конструкторы, инициализаторы переменных, а теперь добавились объектные инициализаторы. Необходимо разобраться, в какой последовательности что выполняется, в том числе при наследовании. При создании экземпляра класса вызванный конструктор выполняется следующим образом:
если первой строкой идет обращение к конструктору родительского класса (явное или добавленное компилятором по умолчанию), то этот конструктор исполняется;
в случае успешного исполнения вызываются все инициализаторы полей и объекта в том порядке, в каком они объявлены в теле класса;
если первой строкой идет обращение к другому конструктору этого же класса, то он вызывается. Повторное выполнение инициализаторов не производится.
Второй пункт имеет ряд важных следствий. Во-первых, из него следует, что в инициализаторах нельзя использовать переменные класса, если их объявление записано позже.
Во-вторых, теперь можно сформулировать наиболее гибкий подход к инициализации final -полей. Главное требование – чтобы такие поля были проинициализированы ровно один раз. Это можно обеспечить в следующих случаях:
если инициализировать поле при объявлении;
если инициализировать поле только один раз в инициализаторе объекта (он должен быть записан после объявления поля);
если инициализировать поле только один раз в каждом конструкторе, в первой строке которого стоит явное или неявное обращение к конструктору родителя. Конструктор, в первой строке которого стоит this, не может и не должен инициализировать final -поле, так как цепочка this -вызовов приведет к конструктору с super, в котором эта инициализация обязательно присутствует.
Для иллюстрации порядка исполнения инициализирующих конструкций рассмотрим следующий пример:
public class Test { { System.out.println('initializer'); } int x, y=getY(); final int z; { System.out.println('initializer2'); } private int getY() { System.out.println('getY() '+z); return z; } public Test() { System.out.println('Test()'); z=3; } public Test(int x) { this(); System.out.println('Test(int)'); // z=4; - нельзя! final-поле уже // было инициализировано } }
После выполнения выражения new Test() на консоли появится:
initializer getY() 0