Чтение онлайн

ЖАНРЫ

Философия Java3

Эккель Брюс

Шрифт:

//: initialization/ArrayClassObj java // Создание массива непримитивных объектов import java.util.*;

import static net.mindview util.Print.*,

public class ArrayClassObj {

' public static void main(String[] args) { Random rand = new Random(47); Integer[] a = new Integer[rand.nextlnt(20)]; print("длина a = " + a.length); for(int i = 0; i < a.length; i++)

a[i] = rand.nextlnt(500); // Автоматическая упаковка

print(Arrays.toString(a)),

}

} /* Output (пример) длина а = 18

[55. 193. 361. 461. 429. 368, 200. 22. 207, 288. 128. 51. 89. 309. 278. 498, 361. 20] *///-

Здесь

даже после вызова new для создания массива

Integer[] а = new Integer[rand nextlnt(20)];

мы имеем лишь массив из ссылок — до тех пор, пока каждая ссылка не будет инициализирована новым объектом Integer (в данном случае это делается посредством автоупаковки):

a[i] = rand.nextlnt(500);

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

Массивы объектов также можно инициализировать списком в фигурных скобках. Существует две формы синтаксиса:

//• i niti ali zati on/ArrayInit java // Инициализация массивов import java.util *;

public class Arraylnit {

public static void main(String[] args) { Integer[] a = {

new Integer(l), new Integer(2), 3, // Autoboxing

}:

Integer[] b = new Integer[]{ new Integer(1), new Integer(2), 3. // Автоматическая упаковка

}:

System. out. pri ntl n (Arrays. toStri ng (a)); System.out println(Arrays.toString(b));

}

} /* Output-[1. 2. 3] [1. 2. 3] *///:-

В обоих случаях завершающая запятая в списке инициализаторов не обязательна (она всего лишь упрощает ведение длинных списков).

Первая форма полезна, но она более ограничена, поскольку может использоваться только в точке определения массива. Вторая форма может использоваться везде, даже внутри вызова метода.

Списки аргументов переменной длины

Синтаксис второй формы предоставляет удобный синтаксис создания и вызова методов с эффектом, напоминающим списки аргументов переменной длины языка С.

Такой список способен содержать неизвестное заранее количество аргументов неизвестного типа. Так как абсолютно все классы унаследованы от общего корневого класса Object, можно создать метод, принимающий в качестве аргумента массив Object, и вызывать его следующим образом:

//. initialization/VarArgs.java

// Использование синтаксиса массивов

// для получения переменного списка параметров.

class А { int i; }

public class VarArgs {

static void printArray(Object[] args) { for(Object obj • args)

System.out print(obj + " "); System out printlnO,

}

public static void main(String[] args) { printArray(new Object[]{

new Integer(47), new Float(3 14), new Double(ll.ll)

}).

printArray(new 0bject[]{"pa3", "два", "три" }); pri ntArray (new Object[]{new AO, new AO, new AO});

}

} /* Output: (Sample) 47 3.14 11.11 раз два три

А@1а46еЗО А@3е25а5 A@19821f *///:-

Видно, что метод print принимает массив объектов типа Object, перебирает его элементы и выводит их. Классы из стандартной библиотеки Java при печати выводят осмысленную информацию, однако объекты классов в данном примере выводят имя класса, затем символ @ и несколько шестнадцатеричных цифр. Таким образом, по умолчанию класс выводит имя и адрес объекта (если только вы не переопределите

в классе метод toString — см. далее).

До выхода Java SE5 переменные списки аргументов реализовывались именно так. В Java SE5 эта долгожданная возможность наконец-то была добавлена в язык — теперь для определения переменного списка аргументов может использоваться многоточие, как видно в определении метода printArray:

//: initialization/NewVarArgs java // Создание списков аргументов переменной длины // с использованием синтаксиса массивов.

public class NewVarArgs {

static void printArray(Object... args) { for(Object obj • args)

System out.print(obj + " "); System.out.printlnO;

}

public static void main(String[] args) {

// Можно передать отдельные элементы printArray(new Integer(47), new Float(3 14), new Doubledl. 11));

printArray(47. 3 14F, 11.11): printArray("раз", "два", "три"): printArray(new АО. new АО, new АО): // Или массив.

printArray((Object[])new Integer[]{ 1, 2, 3, 4 }); printArray, // Пустой список тоже возможен

}

} /* Output- (lb% match) 47 3 14 11.11 47 3 14 11.11 раз два три

A@lbab50a А@сЗс749 A@150bd4d 12 3 4 *///•-

Резюме

Такой сложный механизм инициализации, как конструктор, показывает, насколько важное внимание в языке уделяется инициализации. Когда Бьерн Страуструп разрабатывал С++, в первую очередь он обратил внимание на то, что низкая продуктивность С связана с плохо продуманной инициализацией, которой была обусловлена значительная доля ошибок. Аналогичные проблемы возникают и при некорректной финализации. Так как конструкторы позволяют гарантировать соответствующие инициализацию и завершающие действия по очистке (компилятор не позволит создать объект без вызова конструктора), тем самым обеспечивается полная управляемость и защищенность программы.

В языке С++ уничтожение объектов играет очень важную роль, потому что объекты, созданные оператором new, должны быть соответствующим образом разрушены. В Java память автоматически освобождается сборщиком мусора, и аналоги деструкторов обычно не нужны. В таких случаях сборщик мусора Java значительно упрощает процесс программирования и к тому же добавляет так необходимую безопасность при освобождении ресурсов. Некоторые сборщики мусора могут проводить завершающие действия даже с такими ресурсами, как графические и файловые дескрипторы. Однако сборщики мусора добавляют издержки во время выполнения программы, которые пока трудно реально оценить из-за сложившейся исторически медлительности интерпретаторов Java. И хотя в последнее время язык Java намного улучшил свою производительность, проблема его «задумчивости» все-таки наложила свой отпечаток на возможность решения языком некоторого класса задач.

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

Управление доступом

Поделиться с друзьями: