"valvel = " + valvel + " " + • "valve2 = " + valve2 + " " + "valve3 = " + valve3 + " " +
"valve4 = " + valve4 + "\n" +
••-j = - + -j + ■■ •• + -f = •• + f + •• " +
"source = " + source,
}
public static void main(String[] args) {
SprinklerSystem sprinklers = new SprinklerSystem(), System out println(sprinklers);
}
} /* Output-WaterSourceO
valvel = null valve2 = null valve3 = null valve4 = null i = 0 f = 0.0 source = сконструирован *///•-
В обоих классах определяется особый метод toString(). Позже вы узнаете, что каждый не-примитивный объект имеет метод toString(), который вызывается в специальных случаях, когда компилятор располагает не объектом, а хочет получить его строковое представление в формате String. Поэтому в выражении из метода S р ri n klerSyste m.toStri n g ():
"source = " + source;
компилятор видит, что к строке "source = " «прибавляется» объект класса WaterSource. Компилятор не может это сделать, поскольку к строке можно «добавить» только такую же строку, поэтому он преобразует объект source в String, вызывая метод toString(). После этого компилятор уже в состоянии соединить две строки и передать результат в метод System.out.println() (или статическим методам print() и printnb(), используемым в книге). Чтобы подобное поведение поддерживалось вашим классом, достаточно включить в него метод toString().
Примитивные типы, определенные в качестве полей класса, автоматически инициализируются нулевыми значениями, как упоминалось в главе 2. Однако ссылки на объекты заполняются значениями null, и при попытке вызова метода по такой ссылке произойдет исключение. К счастью, ссылку null можно вывести без выдачи исключения.
Компилятор не создает объекты для ссылок «по умолчанию», и это логично, потому что во многих случаях это привело бы к лишним затратам ресурсов. Если вам понадобится проинициализировать ссылку, сделайте это самостоятельно:
• в точке определения объекта. Это значит, что объект всегда будет инициализироваться перед вызовом конструктора;
• в конструкторе данного класса;
• непосредственно перед использованием объекта. Этот способ часто называют
• с использованием
В следующем примере продемонстрированы все четыре способа:
//: reusing/Bath.java
// Инициализация в конструкторе с композицией.
import static net.mindview.util.Print.*:
class Soap {
private String s: SoapO {
printCSoapO"); s = "Constructed";
}
public String toStringO { return s: }
}
public class Bath {
private String // Инициализация в точке определения-si = "Счастливый", s2 = "Счастливый", s3. s4. private Soap castille; private int i; private float toy; public BathO {
print( В конструкторе BathO"), s3 = "Радостный"; toy = 3.14f; ч castille = new SoapO;
}
// Инициализация экземпляра-
{ i = 47; }
public String toStringO {
if(s4 == null) // Отложенная инициализация-s4 = "Радостный";
return
"si = " + si + "\n" + "s2 = " + s2 + "\n" + "s3 = " + s3 + "\n" + "s4 = " + s4 + "\n" + Hi = " + i + "\n" + "toy = " + toy + "\n" + "castille = " + castille;
}
public static void main(String[] args) { Bath b = new Bath О; print(b);
}
} /* Output; В конструкторе Bath О SoapO
si = Счастливый s2 = Счастливый s3 = Радостный s4 = Радостный i = 47 toy = 3 14
castille = Сконструирован *///;-
Заметьте, что в конструкторе класса Bath команда выполняется до проведения какой-либо инициализации. Если инициализация в точке определения не выполняется, нет никаких гарантий того, что она будет выполнена перед отправкой сообщения по ссылке объекта — кроме неизбежных исключений времени выполнения.
При вызове метода toStringO в нем присваивается значение ссылке s4, чтобы все поля были должным образом инициализированы к моменту их использования.
Синтаксис наследования
Наследование является неотъемлемой частью Java (и любого другого языка ООП). Фактически оно всегда используется при создании класса, потому что, даже если класс не объявляется производным от другого класса, он автоматически становится производным от корневого класса Java Object.
Синтаксис композиции очевиден, но для наследования существует совершенно другая форма записи. При использовании наследования вы фактически говорите: «Этот новый класс похож на тот старый класс». В программе этот факт выражается перед фигурной скобкой, открывающей тело класса: сначала записывается ключевое слово extends, а затем имя
//. reusing/Detergent.java
// Синтаксис наследования и его свойства
import static net mindview util Print.*.
class Cleanser {'