Рейтинговые книги
Читем онлайн Философия Java3 - Брюс Эккель

Шрифт:

-
+

Интервал:

-
+

Закладка:

Сделать
1 ... 90 91 92 93 94 95 96 97 98 ... 132

Массив может содержать примитивные типы, а «старые» контейнеры — нет. С другой стороны, параметризованные контейнеры могут проверять тип хранимых объектов, а благодаря автоматической упаковке они работают так, как если бы поддерживали хранение примитивов, поскольку преобразование выполняется автоматически. В следующем примере массивы сравниваются с параметризованными контейнерами:

//• arrays/Contai nerComparison.java

import java.util *;

import static net mindview.util Print *;

class BerylliumSphere {

private static long counter,

private final long id = counter++;

public String toStringO { return "Sphere " + id; }

}

public class ContainerComparison {

public static void main(String[] args) {

BerylliumSphere[] spheres = new Beryl 1iumSphere[10]; for(int i =0; i <5; i++)

spheres[i] = new Beryl 1iumSphere(), pri nt(Arrays.toStri ng(spheres)); print(spheres[4]);

List<BerylliumSphere> sphereList =

new ArrayLi st<Bery11i umSphere>(), for(int i = 0; i < 5, i++)

sphereList add(new BerylliumSphereO); print(sphereList); print(sphereList.get(4));

int[] integers = { 0, 1. 2, 3. 4, 5 }; pri nt(Arrays.toString(integers)), print(integers[4]);

List<Integer> intList = new ArrayList<Integer>(

Arrays asl_ist(0, 1. 2, 3. 4, 5)); intList.add(97); print(intList);

print(intList get(4)): продолжение &

}

} /* Output

[Sphere 0. Sphere 1. Sphere 2. Sphere 3, Sphere 4, null, null, null. null, null] Sphere 4

[Sphere 5. Sphere 6. Sphere 7. Sphere 8. Sphere 9] Sphere 9

[0. 1, 2. 3. 4. 5] 4

[0. 1. 2. 3. 4. 5. 97] 4

*/// ~

Оба способа хранения объектов обеспечивают проверку типов, а единственное очевидное различие заключается в том, что массивы используют для обращения к элементам конструкцию [], a List — методы вроде add() или get(). Разработчики языка намеренно сделали массивы и ArrayList настолько похожими, чтобы программисту было концептуально проще переключаться между ними. Но, как было показано в главе И, контейнеры обладают более широкими возможностями, чем массивы.

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

Массив как объект

С каким бы типом массива вы ни работали, идентификатор массива в действительности представляет собой ссылку на объект, созданный в динамической памяти. Этот объект содержит ссылки на другие объекты и создается либо неявно (в синтаксисе инициализации массива), либо явно конструкцией new. Одной из частей объекта массива (а по сути, единственным доступным полем) является доступная только для чтения переменная length, которая указывает, сколько элементов может храниться в объекте массива. Весь доступ к объекту массива ограничивается синтаксисом [ ].

Следующий пример демонстрирует различные способы инициализации массивов и присваивания ссылок на массивы. Он также наглядно показывает, что массивы объектов и массивы примитивных типов практически идентичны. Единственное различие заключается в том, что массивы объектов содержат ссылки, а массивы примитивов содержат сами примитивные значения.

//• arrays/ArrayOptions.java

// Инициализация и повторное присваивание массивов

import java util.*,

import static net mindview.util Print *;

public class ArrayOptions {

public static void main(String[] args) { // Массивы объектов.

BerylliumSphere[] a. // Локальная неинициализированная переменная BerylliumSphere[] b = new Beryl 11umSphere[5];

// Ссылки в массиве автоматически инициализируются null printC'b. " + Arrays toString(b)). BerylliumSphere[] с = new Beryl 1iumSphere[4], for(int i =0, i < с length, i++)

if(c[i] == null) // Проверка ссылки на действительность [i] = new Beryl 1iumSphere(), // Агрегатная инициализация. BerylliumSphere[] d = { new Beryl 1iumSphere().

new Beryl 1iumSphere(). new BerylliumSphereO

}.

// Динамическая агрегатная инициализация a = new BerylliumSphere[]{

new Beryl liumSphereO. new Beryl liumSphereO.

}.

// (Завершающая запятая не обязательна в обоих случаях)

print("a.length = " + a length);

printC'b.length = " + b length),

printC'c length = " + с length),

printed length = " + d length);

a = d,

print("a.length = " + a.length);

// Массивы примитивов-int[] e, // Ссылка null int[] f = new int[5],

// Примитивы в массиве автоматически инициализируются нулями

printCf. " + Arrays.toString(f)),

int[] g = new int[4];

for(int i = 0. i < g length. i++)

g[i] = i*i. int:: h = { 11, 47, 93 },

// Ошибка компиляции переменная e не инициализирована

//!printC"е length = " + e.length);

printC'f. length = " + f.length),

printC'g length = " + g length),

printC'h length = " + h.length);

e = h,

printC'e.length = " + e length), e = new int[]{ 1.2}, printC'e. length = " + e.length);

}

} /* Output

b [null, null, null, null, null]

a.length = 2

b.length = 5

c. length = 4 d length = 3 a length = 3

f- [0. 0, 0, 0. 0] f length = 5

g.length = 4

h.length = 3 e.length = 3 e length = 2 *///.-

Массив а — неинициализированная локальная переменная, и компилятор не позволяет что-либо делать с этой ссылкой до тех пор, пока она не будет соответствующим образом инициализирована. Массив b инициализируется массивом ссылок на объекты BerylliumSpere, хотя ни один такой объект в массив не заносится. Несмотря на это, мы можем запросить размер массива, потому что b указывает на действительный объект. В этом проявляется некоторый недостаток массивов: поле length сообщает, сколько элементов может быть помещено в массив, то есть размер объекта массива, а не количество хранящихся в нем элементов. Тем не менее при создании объекта массива все ссылки автоматически инициализируются значением null, и, чтобы узнать, связан ли некоторый элемент массива с объектом, достаточно проверить ссылку на равенство null. Аналогично, массивы примитивных типов автоматически инициализируются нулями для числовых типов: (char)o для char и false для boolean.

Массив с демонстрирует создание массива с последующим присваиванием объектов BerylliumSphere всем элементам массива. Массив d демонстрирует синтаксис «агрегатной инициализации», при котором объект массива создается (с ключевым словом new, как массив с) и инициализируется объектами BerylliumSphere, причем все это происходит в одной команде.

Следующую конструкцию инициализации массива можно назвать «динамической агрегатной инициализацией». Агрегатная инициализация, используемая d, должна использоваться в точке определения d, но при втором синтаксисе объект массива может создаваться и использоваться в любой точке. Предположим, методу hide() передается массив объектов BerylliumSphere. Его вызов может выглядеть так:

hide(d);

однако массив, передаваемый в аргументе, также можно создать динамически:

hide(new BerylliumSphere[]{ new Beryl 1iumSphere(). new BerylliumSphereО });

Во многих ситуациях такой синтаксис оказывается более удобным.

Выражение

a=d;

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

Вторая часть ArrayOptions.java показывает, что примитивные массивы работают точно так же, как массивы объектов, за исключением того, что примитивные значения сохраняются в них напрямую.

Возврат массива

Предположим, вы пишете метод, который должен возвращать не отдельное значение, а целый набор значений. В таких языках, как С и С++, это сделать нелегко, потому что возвращается из метода не массив, а только указатель на массив.

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

В Java вы просто возвращаете массив. Вам не нужно беспокоиться о нем — массив будет существовать до тех пор, пока он вам нужен, а когда надобность в нем отпадет, массив будет уничтожен уборщиком мусора. В качестве примера рассмотрим возвращение массива String:

//: arrays/IceCream.java // Возвращение массивов из методов import java.util.*;

public class IceCream {

private static Random rand = new Random(47); static final String[] FLAVORS = {

"Chocolate". "Strawberry", "Vanilla Fudge Swirl". "Mint Chip". "Mocha Almond Fudge". "Rum Raisin". "Praline Cream". "Mud Pie"

}:

public static String[] flavorSet(int n) { if(n > FLAVORS.length)

throw new IllegalArgumentExceptionC'Set too big"); String[] results = new StringCn]; boolean[] picked = new boolean[FLAVORS.length]; for(int i = 0; i < n; i++) { int t; do

t = rand.nextInt(FLAVORS.length); while(picked[t]); results[i] = FLAVORSCt]: picked[t] = true;

}

return results;

}

public static void main(String[] args) { for(int i = 0; i < 7; i++)

System.out.pri ntin(Arrays.toStri ng(f1 avorSet(3)));

}

} /* Output;

[Rum Raisin. Mint Chip. Mocha Almond Fudge] [Chocolate, Strawberry. Mocha Almond Fudge] [Strawberry. Mint Chip, Mocha Almond Fudge] [Rum Raisin. Vanilla Fudge Swirl. Mud Pie] [Vanilla Fudge Swirl. Chocolate, Mocha Almond Fudge] [Praline Cream. Strawberry. Mocha Almond Fudge] [Mocha Almond Fudge, Strawberry. Mint Chip] *///:-

Метод flavorSet() создает массив results с элементами String. Размер массива равен п; он определяется аргументом, передаваемым при вызове метода. Далее метод случайным образом выбирает элементы из массива FLAVORS и помещает их в массив results, возвращаемый методом. Массив возвращается точно так же, как любой другой объект, — по ссылке. При этом не важно, был ли массив создан методом flavorSet(), или он был создан в другом месте. Массив останется с вами все время, пока он будет нужен, а потом уборщик мусора позаботится о его уничтожении.

Из выходных данных видно, что метод flavorSet() действительно выбирает случайное подмножество элементов при каждом вызове.

Многомерные массивы

Создание многомерных массивов в Java не вызывает особых сложностей. Для многомерных массивов примитивных типов каждый вектор заключается в фигурные скобки:

1 ... 90 91 92 93 94 95 96 97 98 ... 132
На этой странице вы можете бесплатно читать книгу Философия Java3 - Брюс Эккель бесплатно.
Похожие на Философия Java3 - Брюс Эккель книги

Оставить комментарий