Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Java -texnologiya.doc
Скачиваний:
17
Добавлен:
01.05.2025
Размер:
3 Мб
Скачать
☆

7 Public class One {

// Будет создан конструктор по умолчанию

// Родительский класс Object имеет

// конструктор без параметров. }

*Этот класс имеет один конструктор.

V public class Two {// Единственный конструктор класса Second.

// Выражение new Second() ошибочно!

public Second(int х) {} }

*Этот класс имеет два конструктора.

public class Three extends Two { public ThreeO {super(1); // выражение super требуется }

public Three(lnt x) {super(x); // выражение super требуется } }

Если класс имеет более одного конструктора, допускается в первой строке некоторых из них указывать не super, а this - выражение, вызыва­ющее другой конструктор этого же класса.

Рассмотрим следующий пример:

public class Vector { private int vx, vy; protected double length;

public Vector(int x, int y) {superO; vx=x; vy=y;

length=Math.sqrt(vx*vx+vy*vy); }

public Vector(int x1, int y1, int x2, Int у2) {superO;

vx=x2-x1;

vy=y2-y1;

length=Math.sqrt(vx*vx+vy*vy); } }

Видно, что оба конструктора совершают практически идентичные действия, поэтому можно применить более компактный вид записи:

public class Vector { private Int vx, vy; protected double length;

public Vector(int x, Int y) {superO;

vx=x;

vy=y;

length=Math.sqrt(vx*vx+vy*vy); }

public Vector(jnt x1, int y1, int x2, Int у2) {this(x2-x1,y2-y1); } }

Большим достоинством такого метода записи является то, что уда­лось избежать дублирования идентичного кода. Например, если процесс инициализации объектов этого класса удлинится на один шаг (скажем, до­бавится проверка длины на ноль), то такое изменение надо будет внести только в первый конструктор. Такой подход помогает избежать случай­ных ошибок, так как исчезает необходимость тиражировать изменения в нескольких местах.

Разумеется, такое обращение к конструкторам своего класса не должно приводить к зацикливаниям, иначе будет выдана ошибка компиляции. Цепочка this должна в итоге приводить кsuper, который должен присутствовать (явно или неявно) хотя бы в одном из конструкторов. По­сле того, как отработают конструкторы всех родительских классов, будет продолжено выполнение каждого конструктора, вовлеченного в процесс создания объекта.

public class Test { public TestO {System.out.println('Test()"); }

public Test(int x) {thisO;

System.out.println('Test(intx)"); } }

После выполнения выражения new Test(O) на консоли появится:

TestO Testjint X)

В заключение рассмотрим применение модификаторов доступа для конструкторов. Может вызвать удивление возможность объявлять конст­рукторы как private. Ведь они нужны для генерации объектов, а к таким конструкторам ни у кого не будет доступа. Однако в ряде случаев моди­фикатор private может быть полезен. Например:

•   private-конструктор может содержать инициализирующие дейст­вия, а остальные конструкторы будут использовать его с помощью this, причем прямое обращение к этому конструктору по каким-то причинам нежелательно;

•   запрет на создание объектов этого класса, например, невозможно создать экземпляр класса 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("initlallzer");}

intx, y=getY();

final int z;{System.out.println("initializer2");}

private int getY() {System.out.println("getY() "+z);

return z;}

public TestO {System.out.println("Test()");

z=3;}

public Test(int x) {thisO;System.out.println("Test(int)");

// z=4; - нельзя! final-поле уже было инициализировано} }

После выполнения выражения new Test() на консоли появится:

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]