По предыдущим занятиям можно заметить, что фактически уже несколько раз выполнялись операции "компоновки". Для выполнения компоновки достаточно просто поместить ссылки на объекты в новый класс. Например, предположим, что нам требуется хранить несколько объектов типа String
, два примитивных типа данных и один объект другого класса внутри одного объекта. Для неприситивных типов данных достаточно поместить ссылки на них в новый класс, а для примитивных типов данных следует объявить их в своём классе. Пример представлен ниже (если возникают проблемы при запуске программы, обратитесь к разделу 3.1.2 главы 3 "Присваивание").
//: SprinklerSystem.java
// Композиция для повторного использования кода
package c06;
class WaterSource {
private String s;
WaterSource() {
System.out.println("WaterSource()");
s = new String("Создано");
}
public String toString() { return s; }
}
public class SprinklerSystem {
private String valve1, valve2, valve3, valve4;
WaterSource source;
int i;
float f;
void print() {
System.out.println("valve1 = " + valve1);
System.out.println("valve2 = " + valve2);
System.out.println("valve3 = " + valve3);
System.out.println("valve4 = " + valve4);
System.out.println("i = " + i);
System.out.println("f = " + f);
System.out.println("source = " + source);
}
public static void main(String[] args) {
SprinklerSystem x = new SprinklerSystem();
x.print();
}
} ///:~
```Метод `toString()` внутри класса `WaterSource` является особенным. Каждый объект непростого типа имеет метод `toString()`. Если компилятор ожидал получить значение типа `String`, но получил объект данного типа, он будет вызывать этот метод. Поэтому в следующем выражении:```java
System.out.println("источник = " + источник);
Компилятор обнаруживает попытку сложения строки с объектом типа WaterSource
(источник =
). Это недопустимо, так как мы можем складывать только строки, поэтому компилятор говорит: "Я вызову toString()
, чтобы преобразовать источник
в строку!" После этого он может скомпилировать две строки и передать результирующую строку методу System.out.println()
. В каждом случае, когда вы позволяете этому поведению, вам нужно реализовать метод toString()
.
Если не углубляться в детали, можно легко ошибочно полагать, что компилятор автоматически создаёт объект для каждого обращения к нему (в силу образа Java как безопасного и осторожного языка программирования). Например, может показаться, что он вызывает конструктор по умолчанию для WaterSource
, чтобы инициализировать источник
. Однако фактический вывод команды печати выглядит следующим образом:
valve1 = null
valve2 = null
valve3 = null
valve4 = null
i = 0
f = 0.0
источник = null
Как указано в главе 2, базовые данные, используемые как поля внутри класса, инициализируются нулем. В то же время, ссылки на объекты инициализируются значением null
. При попытке вызвать метод для любого из этих объектов будет выброшено исключение. Такое поведение является вполне нормальным (и полезным): мы можем распечатать эти значения без генерации исключения.Компилятор не создаёт по умолчанию объект для каждой ссылки, так как это привело бы к неоправданному увеличению затрат в большинстве случаев. Если требуется инициализация ссылок, это можно сделать в следующих местах:
(1) В момент определения поля. Это означает, что они будут инициализированы до вызова конструктора.
(2) В самом конструкторе класса.
(3) Непосредственно перед тем, как использовать объект. Это позволяет минимизировать необоснованные затраты — если объект не нужен, его создание можно избежать.
Далее представлен пример всех трёх способов инициализации:
//: Bath.java
// Инициализация конструктором с использованием композиции
class Soap {
private String s;
Soap() {
System.out.println("Soap()");
s = new String("Создан");
}
public String toString() { return s; }
}
``````public class Bath {
private String
// Инициализация при определении:
s1 = new String("Счастливый"),
s2 = "Счастливый",
s3, s4;
Soap castille;
int i;
float toy;
Bath() {
System.out.println("Внутри Bath()");
s3 = new String("Радость");
i = 47;
toy = 3.14f;
castille = new Soap();
}
void print() {
// Отложенная инициализация:
if(s4 == null)
s4 = new String("Радость");
System.out.println("s1 = " + s1);
System.out.println("s2 = " + s2);
System.out.println("s3 = " + s3);
System.out.println("s4 = " + s4);
System.out.println("i = " + i);
System.out.println("toy = " + toy);
System.out.println("castille = " + castille);
}
public static void main(String[] args) {
Bath b = new Bath();
b.print();
}
} ///:~
Обратите внимание, что в конструкторе `Bath` перед началом всех инициализаций выполняется один оператор. Если инициализация не происходит при определении, это всё ещё не гарантирует выполнение какой-либо инициализации до отправки сообщения объектному ссылочному значению — за исключением непредотвратимых исключений времени выполнения.
```Вот вывод программы:
```markdown
Внутри Bath()
Soap()
s1 = Happy
s2 = Happy
s3 = Joy
s4 = Joy
i = 47
toy = 3.14
castille = Constructed
При вызове print()
, он заполняет s4
, обеспечивая правильную инициализацию всех полей перед их использованием.
Вы можете оставить комментарий после Вход в систему
Неприемлемый контент может быть отображен здесь и не будет показан на странице. Вы можете проверить и изменить его с помощью соответствующей функции редактирования.
Если вы подтверждаете, что содержание не содержит непристойной лексики/перенаправления на рекламу/насилия/вульгарной порнографии/нарушений/пиратства/ложного/незначительного или незаконного контента, связанного с национальными законами и предписаниями, вы можете нажать «Отправить» для подачи апелляции, и мы обработаем ее как можно скорее.
Опубликовать ( 0 )