Сдам Сам

ПОЛЕЗНОЕ


КАТЕГОРИИ







Операции присваивания и приоритет операций





В завершении рассмотрим операции присваивания, которые в основном представляют комбинацию простого присваивания с другими операциями:

· =

просто приравнивает одно значение другому: c=b;

· +=

c+=b; (переменной c присваивается результат сложения c и b)

· -=

c-=b; (переменной c присваивается результат вычитания b из c)

· *=

c*=b; (переменной c присваивается результат произведения c и b)

· /=

c/=b; (переменной c присваивается результат деления c на b)

· %=

c%=b; (переменной c присваивается остаток от деления c на b)

· &=

c&=b; (переменной c присваивается значение c&b)

· |=

c|=b; (переменной c присваивается значение c|b)

· ^=

c^=b; (переменной c присваивается значение c^b)

· <<=

c<<=b; (переменной c присваивается значение c<<b)

· >>=

c>>=b; (переменной c присваивается значение c>>b)

· >>>=

c>>>=b; (переменной c присваивается значение c>>>b)

Примеры операций:

  inta = 5; a += 10; // 15 a -= 3; // 12 a *= 2; // 24 a /= 6; // 4 a <<= 4; // 64 a >>= 2; // 16 System.out.println(a); // 16

Приоритет операций

При работе с операциями важно понимать их приоритет, который можно описать следующей таблицей:

expr++ expr--
++expr --expr +expr -expr ~!
* / %
+ -
<<>>>>>
<><= >= instanceof
==!=
&
^
|
&&
||
?: (тернарный оператор)
= += -= *= /= %= &= ^= |= <<= >>= >>>= (операторы присваивания)

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

Преобразования базовых типов данных

Каждый базовый тип данных занимает определенное количество байт памяти. Это накладывает ограничение на операции, в которые вовлечены различные типы данных. Рассмотрим следующий пример:

  inta = 4; byteb = a; //!Ошибка

В данном коде мы столкнемся с ошибкой. Хотя и тип byte, и тип int представляют целые числа. Более того значение переменной a, которое присваивается переменной типа byte, вполне укладывается в диапазон значений для типа byte (от -128 до 127). Тем не менее мы сталкиваемся с ошибкой на этапе компиляции. Поскольку в данном случае мы пытаемся присвоить некоторые данные, которые занимают 4 байта, переменной, которая занимет всего один байт.

Тем не менее в программе может потребоваться, чтобы подобное преобразование было выполнено. В этом случае мнеобходимо использовать операцию преобразования типов (операция ()):

  inta = 4; byteb = (byte)a; // преобразование типов: от типа int к типу byte System.out.println(b); // 4

Операция преобразования типов предполагает указание в скобках того типа, к которому надо преобразовать значение. Например, в случае операции (byte)a, идет преобразование данных типа int в тип byte. В итоге мы получим значение типа byte.

Явные и неявные преобразования

Когда в одной операции вовлечены данные разных типов, не всегда необходимо использовать операцию преобразования типов. Некоторые виды преобразований выполняются неявно, автоматически.

Автоматические преобразования

 

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

Автоматически без каких-либо проблем производятся расширяющие преобразования (widening) - они расширяют представление объекта в памяти. Например:

  byteb = 7; intd = b; // преобразование от byte к int

В данном случае значение типа byte, которое занимает в памяти 1 байт, расширяется до типа int, которое занимает 4 байта.

Расширяющие автоматические преобразования представлены следующими цепочками:

byte -> short -> int -> long

int -> double

short -> float -> double

char -> int

Автоматические преобразования с потерей точности

Некоторые преобразования могут производиться автоматически между типами данных одинаковой разрядности или даже от типа данных с большей разрядностью к типа с меньшей разрядностью. Это следующие цепочки преобразований: int -> float, long -> float и long -> double произволятся без ошибок, но при преобразовании мы можем столкнуться с потерей информации.

Например:

  inta = 2147483647; floatb = a; // оттипа int ктипу float System.out.println(b); // 2.14748365E9

Явные преобразования

Во всех остальных преобразованиях примитивных типов явным образом применяется опрерация преобразования типов. Обычно это сужающие преобразования (narrowing) от типа с большей разрядностью к типу с меньшей разрядностью:

  longa = 4; intb = (int) a;

Потеря данных при преобразовании

Применении явных преобразований мы можем столкнуться с потерей данных. Например, следующем коде у нас не возникнет никаких проблем:

  inta = 5; byteb = (byte) a; System.out.println(b); // 5

Число 5 вполне укладывается в диапазон значений типа byte, поэтому после преобразования переменная b будет равна 5. Но что будет в следующем случае:

  inta = 258; byteb = (byte) a; System.out.println(b); // 2

Результатом будет число 2. В данном случае число 258 вне диапазона для типа byte (от -128 до 127), поэтому произойдет усечение значения. Почему результатом будет именно число 2?

Число a, которое равно 258, в двоичном системе будет равно 00000000 00000000 00000001 00000010. Значения типа byte занимают в памяти только 8 байт. Поэтому двоичное представление числа int усекается до 8 правых разрядов, то есть 00000010, что в десятичной системе дает число 2.

Усечение рациональных чисел до целых

При преобразовании значений с плавающей точкой к целочисленным значениям, происходит усечение дробной части:

  doublea = 56.9898; intb = (int)a;

Здесь значение числа b будет равно 56, несмотря на то, что число 57 было бы ближе к 56.9898. Чтобы избежать подобных казусов, надо применять функцию округления, которая есть в математической библиотеке Java:

  doublea = 56.9898; intb = (int)Math.round(a);

Преобразования при операциях

Нередки ситуации, когда приходится применять различные операции, например, сложение и произведение, над значениями разных типов. Здесь также действуют некоторые правила:

· если один из операндов операции относится к типу double, то и второй операнд преобразуется к типу double

· если предыдущее условие не соблюдено, а один из операндов операции относится к типу float, то и второй операнд преобразуется к типу float

· если предыдущие условия не соблюдены, один из операндов операции относится к типу long, то и второй операнд преобразуется к типу long

· иначе все операнды операции преобразуются к типу int

Примеры преобразований:

  inta = 3; doubleb = 4.6; doublec = a+b;

Так как в операции участвует значение типа double, то и другое значение приводится к типу double и сумма двух значений a+b будет представлять тип double.

Другой пример:

  bytea = 3; shortb = 4; bytec = (byte)(a+b);

Две переменных типа byte и short (не double, float или long), поэтому при сложении они преобразуются к типу int, и их сумма a+bпредставляет значение типа int. Поэтому если затем мы присваиваем эту сумму переменной типа byte, то нам опять надо сделать преобразование типов к byte.

Если в операциях участвуют данные типа char, то они преобразуются в int:

  intd = 'a'+ 5; System.out.println(d); // 102

Условные конструкции

Одним из фундаментальных элементов многих языков программирования являются условные конструкции. Данные конструкции позволяют направить работу программы по одному из путей в зависимости от определенных условий.

В языке Java используются следующие условные конструкции: if..else и switch..case

Конструкция if/else

Выражение if/else проверяет истинность некоторого условия и в зависимости от результатов проверки выполняет определенный код:

  intnum1 = 6; intnum2 = 4; if(num1>num2){ System.out.println("Первое число больше второго"); }

После ключевого слова if ставится условие. И если это условие выполняется, то срабатывает код, который помещен в далее в блоке if после фигурных скобок. В качестве условий выступает операция сравнения двух чисел.

Так как, в данном случае первое число больше второго, то выражение num1 > num2 истинно и возвращает значение true. Следовательно, управление переходит в блок кода после фигурных скобок и начинает выполнять содержащиеся там инструкции, а конкретно метод System.out.println("Первое число больше второго");. Если бы первое число оказалось бы меньше второго или равно ему, то инструкции в блоке if не выполнялись бы.

Но что, если мы захотим, чтобы при несоблюдении условия также выполнялись какие-либо действия? В этом случае мы можем добавить блок else:

  intnum1 = 6; intnum2 = 4; if(num1>num2){ System.out.println("Первое число больше второго"); } else{ System.out.println("Первое число меньше второго");

Но при сравнении чисел мы можем насчитать три состояния: первое число больше второго, первое число меньше второго и числа равны. С помощью выражения else if, мы можем обрабатывать дополнительные условия:

  intnum1 = 6; intnum2 = 8; if(num1>num2){ System.out.println("Первое число больше второго"); } elseif(num1<num2){ System.out.println("Первое число меньше второго"); } else{ System.out.println("Числа равны"); }

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

  intnum1 = 8; intnum2 = 6; if(num1 > num2 && num1>7){ System.out.println("Первое число больше второго и больше 7"); }

Здесь блок if будет выполняться, если num1 > num2 равно true и одновременно num1>7 равно true.

Конструкция switch

Конструкция switch/case аналогична конструкции if/else, так как позволяет обработать сразу несколько условий:

  intnum = 8; switch(num){   case1: System.out.println("числоравно 1"); break; case8: System.out.println("числоравно 8"); num++; break; case9: System.out.println("числоравно 9"); break; default: System.out.println("числонеравно 1, 8, 9"); }

После ключевого слова switch в скобках идет сравниваемое выражение. Значение этого выражения последовательно сравнивается со значениями, помещенными после оператора сase. И если совпадение будет найдено, то будет выполняться определенный блок сase.

В конце блока сase ставится оператор break, чтобы избежать выполнения других блоков. Например, если бы убрали бы оператор break в следующем случае:

  case8: System.out.println("числоравно 8"); num++; case9: System.out.println("числоравно 9"); break;

то так как у нас переменная num равно 8, то выполнился бы блок case 8, но так как в этом блоке переменная num увеличивается на единицу, оператор break отсутствует, то начал бы выполняться блок case 9.

Если мы хотим также обработать ситуацию, когда совпадения не будет найдено, то можно добавить блок default, как в примере выше. Хотя блок default необязателен.

Также мы можем определить одно действие сразу для нескольких блоков case подряд:

  intnum = 3; intoutput = 0; switch(num){   case1: output = 3; break; case2: case3: case4: output = 6; break; case5: output = 12; break; default: output = 24; } System.out.println(output);

Тернарная операция

Тернарную операция имеет следующий синтаксис: [первый операнд - условие]? [второй операнд]: [третий операнд]. Таким образом, в этой операции участвуют сразу три операнда. В зависимости от условия тернарная операция возвращает второй или третий операнд: если условие равно true, то возвращается второй операнд; если условие равно false, то третий. Например:

  intx=3; inty=2; intz = x<y? (x+y): (x-y); System.out.println(z);

Здесь результатом тернарной операции является переменная z. Сначала проверяется условие x<y. И если оно соблюдается, то z будет равно второму операнду - (x+y), иначе z будет равно третьему операнду.

Циклы

Еще одним видом управляющих конструкций являются циклы. Циклы позволяют в зависимости от определенных условий выполнять определенное действие множество раз. В языке Java есть следующие виды циклов:

· for

· while

· do...while

Цикл for

Цикл for имеет следующее формальное определение:

  for([инициализация счетчика]; [условие]; [изменение счетчика]) { // действия }

Рассмотрим стандартный цикл for:

  for(inti = 1; i < 9; i++){ System.out.printf("Квадратчисла %d равен %d \n", i, i * i); }

Первая часть объявления цикла - int i = 1 создает и инициализирует счетчик i. Счетчик необязательно должен представлять типint. Это может быть и любой другой числовой тип, например, float. Перед выполнением цикла значение счетчика будет равно 1. В данном случае это то же самое, что и объявление переменной.

Вторая часть - условие, при котором будет выполняться цикл. В данном случае цикл будет выполняться, пока i не достигнет 9.

И третья часть - приращение счетчика на единицу. Опять же нам необязательно увеличивать на единицу. Можно уменьшать: i--.

В итоге блок цикла сработает 8 раз, пока значение i не станет равным 9. И каждый раз это значение будет увеличиваться на 1.

Нам необязательно указывать все условия при объявлении цикла. Например, мы можем написать так:

  inti = 1; for(;;){ System.out.printf("Квадратчисла %d равен %d \n", i, i * i); }

Определение цикла осталось тем же, только теперь блоки в определении у нас пустые: for (;;). Теперь нет инициализированной переменной-счетчика, нет условия, поэтому цикл будет работать вечно - бесконечный цикл.

Либо можно опустить ряд блоков:

  inti = 1; for(; i<9;){ System.out.printf("Квадратчисла %d равен %d \n", i, i * i); i++; }

Этот пример эквивалентен первому примеру: у нас также есть счетчик, только создан он вне цикла. У нас есть условие выполнения цикла. И есть приращение счетчика уже в самом блоке for.

Цикл for может определять сразу несколько переменных и управлять ими:

  intn = 10; for(inti=0, j = n - 1; i < j; i++, j--){   System.out.println(i * j); }

Цикл do

Цикл do сначала выполняет код цикла, а потом проверяет условие в инструкции while. И пока это условие истинно, цикл повторяется. Например:

  intj = 7; do{ System.out.println(j); j--; } while(j > 0);

В данном случае код цикла сработает 7 раз, пока j не окажется равным нулю. Важно отметить, что цикл do гарантирует хотя бы однократное выполнение действий, даже если условие в инструкции while не будет истинно. Так, мы можем написать:

  intj = -1; do{ System.out.println(j); j--; } while(j > 0);

Хотя переменная j изначально меньше 0, цикл все равно один раз выполнится.

Цикл while

Цикл while сразу проверяет истинность некоторого условия, и если условие истинно, то код цикла выполняется:

  intj = 6; while(j >0){   System.out.println(j); j--; }

Операторы continue и break

Оператор break позволяет выйти из цикла в любой его момент, даже если цикл не закончил свою работу:

Например:

  int[] nums = newint[] { 1, 2, 3, 4, 12, 9}; for(inti = 0; i <nums.length; i++){ if(nums[i] > 10) break; System.out.println(nums[i]); }

Так как в цикле идет проверка, больше ли элемент массива 10, то мы не увидим на консоли последние два элемента, так как когда nums[i] окажется больше 10 (то есть равно 12), сработает оператор break, и цикл завершится.

Правда, мы также не увидим и последнего элемента, который меньше 10. Теперь сделаем так, чтобы если число больше 10, цикл не завершался, а просто переходил к следующему элементу. Для этого используем оператор continue:

  int[] nums = newint[] { 1, 2, 3, 4, 12, 9}; for(inti = 0; i <nums.length; i++){   if(nums[i] > 10) continue; System.out.println(nums[i]); }

В этом случае, когда выполнение цикла дойдет до числа 12, которое не удовлетворяет условию проверки, то программа просто пропустит это число и перейдет к следующему элементу массива.

Массивы

Массив представляет набор однотипных значений. Объявление массива похоже на объявление обычной переменной, которая хранит одиночное значение, причем есть два способа объявления массива:

  тип_данных название_массива[]; // либо тип_данных[] название_массива;

Например, определим массив чисел:

  intnums[]; int[] nums2;

После объявления массива мы можем инициализовать его:

  intnums[]; nums = newint[4]; // массивиз 4 чисел

Создание массива производится с помощью следующей конструкции: new тип_данных[количество_элементов], где new - ключевое слово, выделяющее память для указанного в скобках количества элементов. Например, nums = new int[4]; - в этом выражении создается массив из четырех элементов int, и каждый элемент будет иметь значение по умолчанию - число 0.

Также можно сразу при объявлении массива инициализировать его:

  intnums[] = newint[4]; // массивиз 4 чисел int[] nums2 = newint[5]; // массивиз 5 чисел

При подобной инициализации все элементы массива имеют значение по умолчанию. Для числовых типов (в том числе для типа char) это число 0, для типа boolean это значение false, а для остальных объектов это значение null. Например, для типа int значением по умолчанию является число 0, поэтому выше определенный массив nums будет состоять из четырех нулей.

Однако также можно задать конкретные значения для элементов массива при его создании:

  // эти два способа равноценны int[] nums = newint[] { 1, 2, 3, 5};   int[] nums2 = { 1, 2, 3, 5};

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

После создания массива мы можем обратиться к любому его элементу по индексу, который передается в квадратных скобках после названия переменной массива:

  int[] nums = newint[4]; // устанавливаем значения элементов массива nums[0] = 1; nums[1] = 2; nums[2] = 4; nums[3] = 100;   // получаем значение третьего элемента массива System.out.println(nums[2]); // 4

Индексация элементов массива начинается с 0, поэтому в данном случае, чтобы обратиться к четвертому элементу в массиве, нам надо использовать выражение nums[3].

И так как у нас массив определен только для 4 элементов, то мы не можем обратиться, например, к шестому элементу: nums[5] = 5;. Если мы так попытаемся сделать, то мы получим ошибку.

Длина массива

Важнейшее свойство, которым обладают массивы, является свойство length, возвращающее длину массива, то есть количество его элементов:

  int[] nums = {1, 2, 3, 4, 5}; intlength = nums.length; // 5

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

  intlast = nums[nums.length-1];

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

Ранее мы рассматривали одномерные массивы, которые можно представить как цепочку или строку однотипных значений. Но кроме одномерных массивов также бывают и многомерными. Наиболее известный многомерный массив - таблица, представляющая двухмерный массив:

  int[] nums1 = newint[] { 0, 1, 2, 3, 4, 5};   int[][] nums2 = { { 0, 1, 2}, { 3, 4, 5} };

Визуально оба массива можно представить следующим образом:

Одномерный массив nums1

           

Двухмерный массив nums2

     
     

Поскольку массив nums2 двухмерный, он представляет собой простую таблицу. Его также можно было создать следующим образом:int[][] nums2 = new int[2][3];. Количество квадратных скобок указывает на размерность массива. А числа в скобках - на количество строк и столбцов. И также, используя индексы, мы можем использовать элементы массива в программе:

  // установим элемент первого столбца второй строки nums2[1][0]=44; System.out.println(nums2[1][0]);

Объявление трехмерного массива могло бы выглядеть так:

  int[][][] nums3 = newint[2][3][4];

Зубчатый массив

Многомерные массивы могут быть также представлены как "зубчатые массивы". В вышеприведенном примере двухмерный массив имел 3 строчки и три столбца, поэтому у нас получалась ровная таблица. Но мы можем каждому элементу в двухмерном массиве присвоить отдельный массив с различным количеством элементов:

  int[][] nums = newint[3][]; nums[0] = newint[2]; nums[1] = newint[3]; nums[2] = newint[5];

Foreach

Специальная версия цикла for предназначена для перебора элементов в наборах элементов, например, в массивах и коллекциях. Она аналогична действию цикла foreach, который имеется в других языках программирования. Формальное ее объявление:

  for(тип_данных название_переменной: контейнер){ // действия }

Например:

  int[] array = newint[] { 1, 2, 3, 4, 5}; for(inti: array){   System.out.println(i); }

В качестве контейнера в данном случае выступает массив данных типа int. Затем объявляется переменная с типом int

То же самое можно было бы сделать и с помощью обычной версии for:

  int[] array = newint[] { 1, 2, 3, 4, 5}; for(inti = 0; i <array.length; i++){ System.out.println(array[i]); }

В то же время эта версия цикла for более гибкая по сравнению for (int i: array). В частности, в этой версии мы можем изменять элементы:

  int[] array = newint[] { 1, 2, 3, 4, 5}; for(inti=0; i<array.length;i++){ array[i] = array[i] * 2; System.out.println(array[i]); }






Живите по правилу: МАЛО ЛИ ЧТО НА СВЕТЕ СУЩЕСТВУЕТ? Я неслучайно подчеркиваю, что место в голове ограничено, а информации вокруг много, и что ваше право...

ЧТО ПРОИСХОДИТ ВО ВЗРОСЛОЙ ЖИЗНИ? Если вы все еще «неправильно» связаны с матерью, вы избегаете отделения и независимого взрослого существования...

Конфликты в семейной жизни. Как это изменить? Редкий брак и взаимоотношения существуют без конфликтов и напряженности. Через это проходят все...

ЧТО ПРОИСХОДИТ, КОГДА МЫ ССОРИМСЯ Не понимая различий, существующих между мужчинами и женщинами, очень легко довести дело до ссоры...





Не нашли то, что искали? Воспользуйтесь поиском гугл на сайте:


©2015- 2024 zdamsam.ru Размещенные материалы защищены законодательством РФ.