АБОБА. Справочник по программированию на Java Методическое пособие
Скачать 242.41 Kb.
|
Автоматическое повышение типа в выраженияхКроме операций присваивания определенное преобразование типов может выполняться также в выражениях. Для примера рассмотрим следующую ситуацию. Иногда в выражениях в целях обеспечения необходимой точности промежуточное значение может выходить за пределы допустимого диапазона любого из операндов. Например, рассмотрим следующее выражение: byte a = 40; byte b = 50; byte c = 100; int d = a * b / c; Результат вычисления промежуточного члена a*b вполне может выйти за пределы диапазона допустимых значений его операндов типа byte. Для решения подобных проблем при вычислении выражений Java автоматически повышает тип каждого операнда byte или short до int. То есть вычисление промежуточного выражения a*b выполняется с применением целочисленных значений, а не байтов. Поэтому результат промежуточного выражения 50 * 40, равный 2000, оказывается допустимым, несмотря на то, что и для a и для b задан тип byte. Хотя автоматическое повышение типа очень удобно, оно может приводить к досадным ошибкам во время компиляции. Например, следующий внешне абсолютно корректный код приводит к возникновению проблемы: byte b = 50; b = b * 2; // Ошибка! Значение типа int не может быть присвоено // переменной типа byte! Код предпринимает попытку повторного сохранения произведения 50 * 2 – совершенно допустимого значения типа byte – в переменной типа byte. Однако, поскольку во время вычисления выражения тип операндов был автоматически повышен до int, тип результата также был повышен до int. Таким образом, теперь результат выражения имеет тип int, который не может быть присвоен переменной типа byte без приведения типа. Сказанное справедливо даже тогда, когда, как в данном конкретном случае, значение, которое должно быть присвоено, умещается в переменной целевого типа. В тех случаях, когда последствия переполнения понятны, следует использовать явное приведение типов вроде: byte b = 50; b = (byte)(b * 2); , которое приводит к правильному значению, равному 100. Правила повышения типаВ Java определено несколько правил повышения типа, применяемых к выражениям. Эти правила следующие: во-первых, тип всех значений byte, short и char повышается до int, как было описано в предыдущем разделе. Во-вторых, если один операнд имеет тип long, тип всего выражения повышается до long. Если один операнд имеет тип float, тип всего выражения повышается до float. Если любой из операндов имеет тип double, типом результата будет double. Следующая программа демонстрирует повышение типа значения одного из операндов к типу второго в каждой операции с двумя операндами: class Promote { public static void main(String args[]) { byte b = 42; char c = '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); } } Давайте подробнее рассмотрим повышение типа, выполняемое в следующей строке программы: double result = (f * b) + (i / c) – (d * s); В первом промежуточном выражении, f*b, тип переменной b повышается до float, и типом результата вычисления этого промежуточного выражения также является float. В следующем промежуточном выражении i/c тип c повышается до int и результат вычисления этого выражения – int. Затем в выражении d*s тип значения s повышается до double, и все промежуточное выражение получает тип double. И, наконец, выполняются операции с этими тремя промежуточными значениями типов float, int и double. Результат сложения значений типов float и int имеет тип float. Затем тип значения разности результирующего значения типа float и последнего значения типа double повышается до double, который и становится окончательным типом результата выражения. МассивыМассив – это группа однотипных переменных, ссылка на которые выполняется по общему имени. Java допускает создание массивов любого типа, которые могут иметь одно или больше измерений. Доступ к конкретному элементу массива осуществляется по его индексу. Массивы предлагают удобные средства группирования связанной информации. Одномерные массивыОдномерные массивы, по сути, представляют собой список однотипных переменных. Чтобы создать массив, вначале необходимо создать переменную массива требуемого типа. Общая форма объявления одномерного массива выглядит следующим образом: тип имя_переменной[]; Здесь тип задает базовый тип массива. Базовый тип определяет тип данных каждого из элементов, составляющих массив. Таким образом, базовый тип массива определяет тип данных, которые будет содержать массив. Например, следующий оператор объявляет массив month_days, имеющий тип “массив элементов типа int”: int month_days[]; Хотя это объявление утверждает, что month_days – массив переменных, в действительности никакого массива еще не существует. Фактически значение массива month_days установлено равным null, которое представляет массив без значений. Чтобы связать month_days с реальным физическим массивом целочисленных значений, необходимо с помощью операции new распределить память и присвоить ее массиву month_days. Подробнее мы рассмотрим эту операцию в следующей главе, однако она нужна сейчас для выделения памяти под массивы. Общая форма операции new применительно к одномерным массивам выглядит следующим образом: переменная_массива = new тип[размер]; тип определяет тип данных, для которых резервируется память, размер указывает количество элементов в массиве, а переменная_массива – переменная массива, связанная с массивом. То есть, чтобы использовать операцию new для распределения памяти, потребуется указать тип и количество элементов, для которых нужно зарезервировать память. Элементы массива, для которых память была выделена операцией new, будут автоматически инициализированы нулевыми значениями. Следующий оператор резервирует память для 12-элементного массива целых значений и связывает их с массивом month_days. month_days = new int[12]; После выполнения этого оператора month_days будет ссылаться на массив, состоящий из 12 целочисленных значений. При этом все элементы массива будут инициализированы нулевыми значениями. Как только массив создан, и память для него распределена, к конкретному элементу массива можно обращаться, указывая его индекс в квадратных скобках. Индексы массива начинаются с нуля. Например, следующий оператор присваивает значение 28 второму элементу массива month_days: month_days[1] = 28; Следующая строка кода отображает значение, хранящееся в элементе с индексом, равным 3: System.out.println(month_days[3]); Чтобы продемонстрировать весь процесс в целом, приведем программу, которая создает массив числа дней в каждом месяце. // Демонстрация использования одномерного массива. class Array { public static void main(String args[]) { int month_days[]; BookNew_JAVA-7.indb 84 02.06.2007 1:06:38 Глава 3. Типы данных, переменные и массивы 85 month_days = new int[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] = 31; System.out.println("В апреле " + month_days[3] + " дней."); } } Если выполнить эту программу, она выведет количество дней в апреле. Как уже было сказано, в Java индексация элементов массивов начинается с нуля, поэтому количество дней в апреле – month_days[3], или 30. Объявление переменной массива можно объединять с распределением самого массива, как показано в следующем примере: int month_days[] = new int[12]; Именно так обычно и поступают в профессионально написанных Java-программах. Массивы можно инициализировать при их объявлении. Этот процесс во многом аналогичен инициализации простых типов. Инициализатор массива – это разделяемый запятыми список выражений, заключенный в фигурные скобки. Запятые разделяют значения элементов массива. Массив будет автоматически создан достаточно большим, чтобы в нем могли уместиться все элементы, указанные в инициализаторе массива. В этом случае использование операции new не требуется. Например, чтобы сохранить количество дней каждого месяца, можно использовать следующий код, который создает и инициализирует массив целых значений: // Усовершенствованная версия предыдущей программы. class AutoArray { public static void main(String args[]) { int month_days[] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; System.out.println("В апреле " + month_days[3] + " дней."); } } При выполнении этой программы она генерирует такой же вывод, как и предыдущая версия. Система Java выполняет тщательную проверку, чтобы убедиться в том, не была ли случайно предпринята попытка сохранения или ссылки на значения, которые выходят за пределы допустимого диапазона массива. Система времени выполнения Java будет проверять соответствие всех индексов массива допустимому диапазону. Например, система времени выполнения будет проверять соответствие значения каждого индекса допустимому диапазону от 0 до 11 включительно. Попытка обращения к элементам за пределами диапазона массива (указание отрицательных индексов или индексов, которые превышают длину массива) приведет к ошибке времени выполнения. Приведем еще один пример программы, в которой используется одномерный массив. Эта программа вычисляет среднее значение набора чисел. // Вычисление среднего значения массива значений. class Average { public static void main(String args[]) { double nums[] = {10.1, 11.2, 12.3, 13.4, 14.5}; double result = 0; int i; for(i=0; i<5; i++) result = result + nums[i]; System.out.println("Среднее значение равно " + result / 5); } } |