Главная страница

Java. Полное руководство. 8-е издание. С. Н. Тригуб Перевод с английского и редакция


Скачать 25.04 Mb.
НазваниеС. Н. Тригуб Перевод с английского и редакция
АнкорJava. Полное руководство. 8-е издание.pdf
Дата28.02.2017
Размер25.04 Mb.
Формат файлаpdf
Имя файлаJava. Полное руководство. 8-е издание.pdf
ТипДокументы
#3236
страница7 из 90
1   2   3   4   5   6   7   8   9   10   ...   90
8 Часть I. Язык Чтобы выполнить преобразование между двумя несовместимыми типами, необходимо использовать приведение типов. Приведение — это всего лишь явное преобразование типов. Общая форма преобразования имеет вид.
(
целевой_ тип
)
значение
Здесь целевой тип определяет тип, в который нужно преобразовать указанное значение. Например, следующий фрагмент кода приводит тип i n t к типу b y te . Если значение целочисленного типа больше допустимого диапазона типа b y t e , оно будет уменьшено до результата деления по модулю (остатка от целочисленного деления) на диапазон типа b y te .
int а
byte b;
/ / . .
b = (byte) При присваивании значения с плавающей точкой переменной целочисленного типа выполняется другой вид преобразования типа — усечение. Как вызнаете, целые числа не содержат дробной части. Таким образом, когда значение с плавающей точкой присваивается переменной целочисленного типа, дробная часть отбрасывается. Например, в случае присваивания значения 1,23 целочисленной переменной результирующим значением будет просто 1. Дробная часть — 0,23 — усекается. Конечно, если размер целочисленной части слишком велик, чтобы уместиться в целевом целочисленном типе, значение будет уменьшено до результата деления по модулю на диапазон целевого типа.
Следующая программа демонстрирует ряд преобразований типа, которые требуют приведения Демонстрация приведения типов
class Conversion {
public static void main(String a r g s []) {
byte b;
int i = 2 57;
double d = 323.142;
System.out.println("ХпПреобразование int в byte.");
b = (byte) i;
System.out.println("i и b " + i + " " + b) ;
System.out.println("ХпПреобразование double в int.");
i = (int) d;
System.out.println("d и i " + d + " " + i);
System.out.println("ХпПреобразование double в byte.");
b = (byte) d;
System.out.println("d и b " + d + " " + b ) Эта программа создает следующий вывод.
Преобразование int в byte,
i и
b
257 Преобразование double в int.
d и i 323.142 Преобразование double в byte,
d ив Глава 3. Типы данных, переменные и массивы Рассмотрим каждое из этих преобразований. Когда значение 257 приводится к типу byte, результатом будет остаток отделения на 256 (диапазон допустимых значений типа byte), который в данном случае равен 1. Когда значение переменной
d преобразуется в тип int, его дробная часть отбрасывается. Когда значение переменной
d преобразуется в тип byte, его дробная часть отбрасывается и значение уменьшается до результата деления по модулю на 256, который в данном случае равен Автоматическое повышение типа в выражениях
Кроме операций присваивания, определенное преобразование типов может выполняться также в выражениях. Для примера рассмотрим следующую ситуацию. Иногда в выражениях для обеспечения необходимой точности промежуточное значение может выходить за пределы допустимого диапазона любого из операндов. Например, рассмотрим следующее выражение аса с;

Результат вычисления промежуточного члена а*Ь вполне может выйти за пределы диапазона допустимых значений его операндов типа byte. Для решения подобных проблем при вычислении выражений Java автоматически повышает тип каждого операнда byte или short до int. То есть вычисление промежуточного выражения а*Ь выполняется с применением целочисленных значений, а не байтов. Поэтому результат промежуточного выражения 50*40, равный 2000, оказывается допустимым, несмотря на то что и для аи для b задан тип Хотя автоматическое повышение типа очень удобно, оно может приводить к досадным ошибкам вовремя компиляции. Например, следующий внешне абсолютно корректный код приводит к возникновению проблемы b = 50;

b = b * 2; // Ошибка Значение типа int не может быть присвоено
// переменной типа Код предпринимает попытку повторного сохранения произведения
5 0
*
2
— совершенно допустимого значения типа byte
— в переменной типа byte. Однако поскольку вовремя вычисления выражения тип операндов был автоматически повышен до int, тип результата также был повышен до int. Таким образом, теперь результат выражения имеет тип int, который не может быть присвоен переменной типа byte без приведения типа. Сказанное справедливо даже тогда, когда, как в данном конкретном случае, значение, которое должно быть присвоено, умещается в переменной целевого типа.
В тех случаях, когда последствия переполнения понятны, следует использовать явное приведение типов b = 50;

b = (byte)(b * которое приводит к правильному значению, равному 100.

8 8 Часть I. Язык Правила повышения типа
В Java определено несколько правил повышения типа, применяемых к выражениям. Во-первых, тип всех значений byte, short и char повышается до int, как было описано в предыдущем разделе. Во-вторых, если один операнд имеет тип long, тип всего выражения повышается до long. Если один операнд имеет тип float, тип всего выражения повышается до float. Если любой из операндов имеет тип double, типом результата будет Следующая программа демонстрирует повышение типа значения одного из операндов к типу второго в каждом операторе с двумя операндами
class Promote {
public static void main(String a r g s []) {
byte b = 42;
char с = 'a ';
short s = 1024;
int i = 50000;
float f = 5.67f ;
double d = .1234;
double result = (f * b) + (i / c) - (d * s);
System.out.println((f * b) + " + " + (i / c) + " — " + (d * s));
System.out.println("result = " + Давайте подробнее рассмотрим повышение типа, выполняемое в следующей строке программы result = (f * b) + (i / с) - (d * В первом промежуточном выражении, f
*b, тип переменной b повышается дои типом результата вычисления этого промежуточного выражения также является float. В следующем промежуточном выражении i/c тип с повышается дои результат вычисления этого выражения — int. Затем в выражении d*s тип значения s повышается дои все промежуточное выражение получает тип double. И наконец, выполняются операции с этими тремя промежуточными значениями типов float, int и double. Результат сложения значений типов float и int имеет тип float. Затем тип значения разности результирующего значения типа float и последнего значения типа double повышается до double, который и становится окончательным типом результата выражения.
Массивы
Массив — это группа однотипных переменных, для обращения к которым используется общее имя. Java допускает создание массивов любого типа, которые могут иметь одно или несколько измерений. Доступ к конкретному элементу массива осуществляется по его индексу. Массивы предлагают удобный способ группирования связанной информации.
На заметку Те, кто знаком с языками C/C++, должны быть особенно внимательны. В Java массивы работают не так, как в этих языках.

Одномерные массивы
По сути, одномерные массивы представляют собой список однотипных переменных. Чтобы создать массив, вначале необходимо создать переменную массива тре­
Глава 3. Типы данных, переменные и массивы 9
буемого типа. Общая форма объявления одномерного массива выглядит следующим образом.
тип имя_переменной
[
]
Здесь тип задает тип элемента (называемый также базовым типом) массива. Тип элемента определяет тип данных каждого из элементов, составляющих массив. Таким образом, тип элемента массива определяет тип данных, которые будет содержать массив. Например, следующий оператор объявляет массив month_ days, имеющий тип массив элементов типа int”.
int Хотя это объявление утверждает, что month_day s
— массив переменных, в действительности никакого массива еще не существует. Фактически значение массива month_days установлено равным null, которое представляет массив без значений. Чтобы связать имя month_days с реальным физическим массивом целочисленных значений, необходимо с помощью оператора new зарезервировать память и присвоить ее массиву Подробнее мы рассмотрим эту операцию в следующей главе, однако она нужна сейчас для выделения памяти под массивы. Общая форма оператора new применительно к одномерным массивам выглядит следующим образом.
переменная_массива
= new тип размер Здесь тип определяет тип данных, для которых резервируется память, размер указывает количество элементов в массиве, а переменная массива переменная массива, связанная с массивом. Другими словами, чтобы использовать оператор new для резервирования памяти, потребуется указать тип и количество элементов, для которых нужно зарезервировать память. Элементы массива, для которых память была выделена оператором new, будут автоматически инициализированы нулевыми значениями (для числовых типов, значениями false для логического типа) или значениями null для ссылочных типов, рассматриваемых в следующей главе. Приведенный ниже оператор резервирует память для элементного массива целых значений и связывает их с массивом month_days.
month_days = new i n t После выполнения этого оператора month_days будет ссылаться на массив, состоящий из 12 целочисленных значений. При этом все элементы массива будут инициализированы нулевыми значениями.
Подведем итоги создание массива — двухэтапный процесс. Во-первых, необходимо объявить переменную нужного типа массива. Во-вторых, с помощью оператора new необходимо зарезервировать память для хранения массива и присвоить ее переменной массива. Таким образом, в Java все массивы являются динамически распределяемыми. Если вы еще незнакомы с концепцией динамического распределения памяти, не беспокойтесь. Этот процесс будет подробно описан в последующих главах книги.
Как только массив создан и память для него зарезервирована, к конкретному элементу массива можно обращаться, указывая его индекс в квадратных скобках. Индексы массива начинаются с нуля. Например, следующий оператор присваивает значение 28 второму элементу массива month_days.
month_days[1] = Следующая строка кода отображает значение, хранящееся в элементе с индексом, равным Чтобы продемонстрировать весь процесс в целом, приведем программу, которая создает массив количества дней в каждом месяце

9 0 Часть I. Язык Java
// Демонстрация использования одномерного массива
class Array {
public static void main(String a r g s []) {
int month_days[];
month_days = new i n t [12];
month_days[0]
= 31
month_days[1]
= 28
month_days[2]
= 31
month_days[3]
= 30
month_days[4]
= 31
month_days[5]
= 30
month_days[6]
= 31
month_days[7]
= 31
month_days[8]
= 30
month_days[9]
= 31
month_days[10]
= 30;
month_days[11 ] = В апреле " + month_days[3] + " дней."
}
}
Если выполнить эту программу, она выведет количество дней в апреле. Как уже было сказано, в Java индексация элементов массивов начинается с нуля, поэтому количество дней в апреле — m o n th _ d ay s [ 3 ], или Объявление переменной массива можно объединять с распределением самого массива, как показано в следующем примере month_days[] = new i n t Именно так обычно и поступают в профессионально написанных программах
Java. Массивы можно инициализировать при их объявлении. Этот процесс во многом аналогичен инициализации простых типов. Инициализатор массива — это разделяемый запятыми список выражений, заключенный в фигурные скобки. Запятые разделяют значения элементов массива. Массив будет автоматически создан достаточно большим, чтобы в нем могли уместиться все элементы, указанные вини циализаторе массива. В этом случае использование оператора new не требуется. Например, чтобы сохранить количество дней каждого месяца, можно использовать следующий код, который создает и инициализирует массив целых значений Усовершенствованная версия предыдущей программы
class AutoArray {
public static void main(String a r g s []) {
int month_days[] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31,
30, 31 В апреле " + month_days[3] + " дней.");
}
}
П ри выполнении эта программа выдает такой же результат, как и предыдущая версия.
Система Java выполняет тщательную проверку, чтобы убедиться в том, не была ли случайно предпринята попытка присвоения или обращения к значениям, которые выходят за пределы допустимого диапазона массива. Система времени выполнения Java будет проверять соответствие всех индексов массива допустимому диапазону. Например, система времени выполнения будет проверять соответствие значения каждого индекса допустимому диапазону от 0 до 11 включительно. Попытка обращения к элементам за пределами диапазона массива (указание отри-
Глава 3. Типы данных, переменные и массивы
91
дательных индексов или индексов, которые превышают длину массива) приведет к ошибке времени выполнения.
Приведем еще один пример программы, в которой используется одномерный массив. Эта программа вычисляет среднее значение набора чисел Вычисление среднего значения массива значений
class Average {
public static void main(String a r g s []) {
double n u m s [] = {10.1, 11.2, 12.3, 13.4, 14.5};
double result = 0;
int i ;
for(i=0; i<5; i++)
result = result + Среднее значение равно " + result / Многомерные массивы
В Java многомерные массивы представляют собой массивы массивов. Они, как можно догадаться, выглядят и действуют подобно обычным многомерным массивам. Однако, как вы увидите, они имеют несколько незначительных отличий. При объявлении переменной многомерного массива для указания каждого дополнительного индекса используют отдельный набор квадратных скобок. Например, следующий код объявляет переменную двухмерного массива twoD.
int t w o D [][] = new i n t [4] Этот оператор резервирует память для массива размерностью 4x5 и присваивает его переменной twoD. Внутренне эта матрица реализована как массив массивов значений типа i n t . Сточки зрения логической организации этот массив будет выглядеть подобно изображенному на рис. Следующая программа нумерует элементы в массиве слева направо, сверху вниз, а затем отображает эти значения Демонстрация двухмерного массива
class TwoDArray {
public static void main(String a r g s []) {
int twoD[][]= new i n t [4] [5];
int i ,
j ,
k = 0;
for(i=0; i<4; i++)
for(j=0; j<5; j++) {
t w o D [i ][j ] = k ;
k++;
}
f o r (i=0; i<4; i++) {
for(j=0; j <5; j++)
System.out.print(twoD[i][j] + " ");
System.out.println();
}
}
}

9 2 Часть I. Язык Правый индекс определяет столбец I I I Дано int twoD[] [] = new int[4] [5] Рис. 3.1. Логическое представление двухмерного массива Эта программа создает следующий вывод 1 2 3 4
5 6 7 8 9
10 11 12 13 14
15 16 17 18 При резервировании памяти под многомерный массив необходимо указать память только для первого (левого) измерения. Для каждого из остальных измерений память можно резервировать отдельно. Например, следующий код резервирует память для первого измерения массива twoD при его объявлении. Резервирование памяти для второго измерения массива осуществляется вручную twoD [ ]
[
]
= new m t [ 4 ] [] ;
twoD[0] = new i n t [5];
t w o D [1] = new i n t [5];
t w o D [2] = new i n t [5];
t w o D [3] = new Хотя в данной ситуации отдельное резервирование памяти для второго измерения массива и не дает никаких преимуществ, в других ситуациях это может быть полезно. Например, при резервировании памяти для измерений массива вручную, ненужно резервировать одинаковое количество элементов для каждого измерения. Как было отмечено ранее, поскольку в действительности многомерные массивы представляют собой массивы массивов, программист полностью управляет длиной каждого массива. Например, следующая программа создает двухмерный массив с различными размерами второго измерения Резервирование памяти вручную для массива с различными
// размерами второго измерения
class T w o D A g a m {
public static void main(String a r g s []) {
Глава 3. Типы данных, переменные и массивы 3
int twoD[][] = new i n t [4][3;
twoD[0]
= new
m t [ l ] ;
twoD[l]
= new
i n t [2];
t w o D [2]
= new
i n t [3];
t w o D [3]
= new
i n t [4];
int i ,
j к = 0;
f o r (i=0; i<4; i
+
+)
fo r (j =
0; j <
i
+1; j++) {
t w o D [i ][j ]
= k;
k++;
}
for(i=0; i<4; i++) {
fo r (j =
0; j <
i
+1; j++)
System.out.p r i n t (t w o D [i][j ] + " ");
System.out.p r Эта программа создает следующий вывод 1 2
3 4 5
6 7 8 Созданный ею массив выглядит, как показано на рис. Использование неоднородных (или нерегулярных) массивов может быть неприменимо во многих приложениях, поскольку их поведение отличается от обычного поведения многомерных массивов. Однако в некоторых ситуациях нерегулярные массивы могут оказаться весьма эффективными. Например, нерегулярный массив может быть идеальным решением, если требуется очень большой двухмерный разреженный массив (те. массив, в котором будут использоваться не все элементы).
Многомерные массивы можно инициализировать. Для этого достаточно заключить инициализатор каждого измерения в отдельный набор фигурных скобок. Следующая программа создает матрицу, в которой каждый элемент содержит произведение индексов строки и столбца. Обратите также внимание на то, что внутри инициализаторов массивов можно применять как литеральное значение, таки вы­
ражения.
Рис. 3.2. Двухмерный массив с различными размерами второго измерения Часть I. Язык Java
1   2   3   4   5   6   7   8   9   10   ...   90


написать администратору сайта