русс | укр

Языки программирования

ПаскальСиАссемблерJavaMatlabPhpHtmlJavaScriptCSSC#DelphiТурбо Пролог

Компьютерные сетиСистемное программное обеспечениеИнформационные технологииПрограммирование

Все о программировании


Linux Unix Алгоритмические языки Аналоговые и гибридные вычислительные устройства Архитектура микроконтроллеров Введение в разработку распределенных информационных систем Введение в численные методы Дискретная математика Информационное обслуживание пользователей Информация и моделирование в управлении производством Компьютерная графика Математическое и компьютерное моделирование Моделирование Нейрокомпьютеры Проектирование программ диагностики компьютерных систем и сетей Проектирование системных программ Системы счисления Теория статистики Теория оптимизации Уроки AutoCAD 3D Уроки базы данных Access Уроки Orcad Цифровые автоматы Шпаргалки по компьютеру Шпаргалки по программированию Экспертные системы Элементы теории информации

Операторы сдвига


Дата добавления: 2015-06-12; просмотров: 1108; Нарушение авторских прав


Операторы сдвига также манипулируют битами и используются только с примитивными целочисленными типами. Оператор сдвига влево (<<) сдвигает влево операнд, находящийся слева от оператора, на количество битов, указанное после оператора. Оператор сдвига вправо (>>) сдвигает вправо операнд, находящийся слева от оператора, на количество битов, указанное после оператора. При сдвиге вправо используется заполнение знаком: при положительном значении новые биты заполняются нулями, а при отрицательном — единицами.

В Java также поддерживается беззнаковый сдвиг вправо (>>>), использующий заполнение нулями: независимо от знака старшие биты заполняются нулями. Такой оператор не имеет аналогов в C и C++.

Если сдвигаемое значение относится к типу char, byte или short, эти типы приводятся к int перед выполнением сдвига, и результат также получится int. При этом используется только пять младших битов с «правой» стороны. Таким образом, нельзя сдвинуть битов больше, чем вообще существует для целого числа int. Если вы проводите операции с числами long, то получите результаты типа long. При этом будет задействовано только шесть младших битов с «правой» стороны, что предотвращает использование излишнего числа битов.

Сдвиги можно совмещать со знаком равенства (<<=, или >>=, или >>>=). Именующее выражение заменяется им же, но с проведенными над ним операциями сдвига. Однако при этом возникает проблема с оператором беззнакового правого сдвига, совмещенного с присвоением. При использовании его с типом byte или short вы не получите правильных результатов. Вместо этого они сначала будут преобразованы к типу int и сдвинуты вправо, а затем обрезаны при возвращении к исходному типу, и результатом станет -1. Следующий пример демонстрирует это:

//: operators/URShift.java



// Проверка беззнакового сдвига вправо

import static net.mindview.util.Print.*;

 

public class URShift {

public static void main(String[] args) {

int i = -1;

print(Integer.toBinaryString(i));

i >>>= 10;

print(Integer.toBinaryString(i));

long l = -1;

print(Long.toBinaryString(l));

l >>>= 10;

print(Long.toBinaryString(l));

short s = -1;

print(Integer.toBinaryString(s));

s >>>= 10;

print(Integer.toBinaryString(s));

byte b = -1;

print(Integer.toBinaryString(b));

b >>>= 10;

print(Integer.toBinaryString(b));

b = -1;

print(Integer.toBinaryString(b));

print(Integer.toBinaryString(b>>>10));

}

}

<spoiler text="Output:">

</spoiler> В последней команде программы полученное значение не приводится обратно к b, поэтому получается верное действие.

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

//: operators/BitManipulation.java

// Использование поразрядных операторов.

import java.util.*;

import static net.mindview.util.Print.*;

 

public class BitManipulation {

public static void main(String[] args) {

Random rand = new Random(47);

int i = rand.nextInt();

int j = rand.nextInt();

printBinaryInt("-1", -1);

printBinaryInt("+1", +1);

int maxpos = 2147483647;

printBinaryInt("maxpos", maxpos);

int maxneg = -2147483648;

printBinaryInt("maxneg", maxneg);

printBinaryInt("i", i);

printBinaryInt("~i", ~i);

printBinaryInt("-i", -i);

printBinaryInt("j", j);

printBinaryInt("i & j", i & j);

printBinaryInt("i | j", i | j);

printBinaryInt("i ^ j", i ^ j);

printBinaryInt("i << 5", i << 5);

printBinaryInt("i >> 5", i >> 5);

printBinaryInt("(~i) >> 5", (~i) >> 5);

printBinaryInt("i >>> 5", i >>> 5);

printBinaryInt("(~i) >>> 5", (~i) >>> 5);

 

long l = rand.nextLong();

long m = rand.nextLong();

printBinaryLong("-1L", -1L);

printBinaryLong("+1L", +1L);

long ll = 922337207L;

printBinaryLong("maxpos", ll);

long lln = -922337208L;

printBinaryLong("maxneg", lln);

printBinaryLong("l", l);

printBinaryLong("~l", ~l);

printBinaryLong("-l", -l);

printBinaryLong("m", m);

printBinaryLong("l & m", l & m);

printBinaryLong("l | m", l | m);

printBinaryLong("l ^ m", l ^ m);

printBinaryLong("l << 5", l << 5);

printBinaryLong("l >> 5", l >> 5);

printBinaryLong("(~l) >> 5", (~l) >> 5);

printBinaryLong("l >>> 5", l >>> 5);

printBinaryLong("(~l) >>> 5", (~l) >>> 5);

}

static void printBinaryInt(String s, int i) {

print(s + ", int: " + i + ", binary:\n " +

Integer.toBinaryString(i));

}

static void printBinaryLong(String s, long l) {

print(s + ", long: " + l + ", binary:\n " +

Long.toBinaryString(l));

}

}

<spoiler text="Output:">

-1, int: -1, binary:

+1, int: 1, binary:

maxpos, int: 2147483647, binary:

maxneg, int: -2147483648, binary:

i, int: -1172028779, binary:

~i, int: 1172028778, binary:

-i, int: 1172028779, binary:

j, int: 1717241110, binary:

i & j, int: 570425364, binary:

i | j, int: -25213033, binary:

i ^ j, int: -595638397, binary:

i << 5, int: 1149784736, binary:

i >> 5, int: -36625900, binary:

(~i) >> 5, int: 36625899, binary:

i >>> 5, int: 97591828, binary:

(~i) >>> 5, int: 36625899, binary:

</spoiler> Два метода в конце, printBinaryInt() и printBinaryLong(), получают в качестве параметров, соответственно, числа int и long и выводят их в двоичном формате вместе с сопроводительным текстом. Вместе с демонстрацией поразрядных опе­раций для типов int иlong этот пример также выводит минимальное и максимальное значение, +1 и -1 для этих типов, чтобы вы лучше понимали, как они выглядят в двоичном представлении. Заметьте, что старший бит обозначает знак: 0 соответствует положительному и 1 — отрицательному числам. Результат работы для типа int приведен в конце листинга

 

Тернарный оператор «если-иначе»

Тернарный оператор необычен тем, что он использует три операнда. И все же это действительно оператор, так как он производит значение, в отличие от обычной конструкции выбора if-else, описанной в следующем разделе. Выражение записывается в такой форме:

логическое-условие ? выражение0 : выражение1

Если логическое-условие истинно (true), то затем вычисляется выражение0, и именно его результат становится результатом выполнения всего оператора. Если же логическое-условие ложно (false), то вычисляется выражение1, и его значение становится результатом работы оператора. Пример использования тернарного оператора:

//: operators/TernaryIfElse.java

import static net.mindview.util.Print.*;

 

public class TernaryIfElse {

static int ternary(int i) {

return i < 10 ? i * 100 : i * 10;

}

static int standardIfElse(int i) {

if(i < 10)

return i * 100;

Else

return i * 10;

}

public static void main(String[] args) {

print(ternary(9));

print(ternary(10));

print(standardIfElse(9));

print(standardIfElse(10));

}

}

<spoiler text="Output:">

</spoiler> Конечно, здесь можно было бы использовать стандартную конструкцию if-else (описываемую чуть позже), но тернарный оператор гораздо компактнее. Хотя C (где этот оператор впервые появился) претендует на звание лаконичного языка, и тернарный оператор вводился отчасти для достижения этой цели, будьте благоразумны и не используйте его всюду и постоянно — он может ухудшить читаемость программы.

 

Операторы + и += для String

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

При создании C++ в язык была добавлена возможность перегрузки операторов, позволяющей программистам C++ изменять и расширять смысл почти любого оператора. К сожалению, перегрузка операторов, в сочетании с некоторыми ограничениями C++, создала немало проблем при проектировании классов. Хотя реализацию перегрузки операторов в Java можно было осуществить проще, чем в C++ (это доказывает язык C#, где существует простой механиз перегрузки), эту возможность все же посчитали излишне сложной, и поэтому программистам на Java не дано реализовать свои собственные перегруженные операторы, как это делают программисты на C++.

Использование + и += для строк (String) имеет интересные особенности. Если выражение начинается строкой, то все последующие операнды также будут предварительно преобразованы в строчное представление! (помните, что компилятор превращает символы в кавычках в объект String).

int х = 0; у = 1; z = 2;

String s = "х, у, z";

System.out.println(s + x + у + z),

В данном случае компилятор Java приводит переменные х, у и z к их строковому представлению, вместо того чтобы сначала арифметически сложить их. А если вы запишете

System.out.println(x + s);

то и здесь Java преобразует x в строку.

 

Типичные ошибки при использовании операторов

Многие программисты склонны второпях записывать выражение без скобок, даже когда они не уверены в последовательности вычисления выражения. Это верно и для Java.

Еще одна распространенная ошибка в C и C++ выглядит следующим образом:

while(x = у) { // .

}

Программист хотел выполнить сравнение (==), а не присвоение. В C и C++ результат этого выражения всегда будет истинным, если только у не окажется нулем; вероятно, возникнет бесконечный цикл. В языке Java результат такого выражения не будет являться логическим типом (boolean), а компилятор ожидает в этом выражении именно boolean и не разрешает использовать целочисленный тип int, поэтому вовремя сообщит вам об ошибке времени компиляции, упредив проблему еще перед запуском программы. Поэтому подобная ошибка вJava никогда не происходит. (Программа откомпилируется только в одном случае: если х и у одновременно являются типами boolean, и тогда выражение х = у будет допустимо, что может привести к ошибке.)

Похожая проблема возникает в C и C++ при использовании поразрядных операторов И и ИЛИ вместо их логических аналогов. Поразрядные И и ИЛИ записываются одним символом (& и |), в то время как логические И и ИЛИ требуют в написании двух символов (&& и ||). Так же, как и в случае с операторами = и ==, легко ошибиться и набрать один символ вместо двух. В Java компилятор предотвращает такие ошибки, так как он не позволяет использовать тип данных в неподходящем контексте.

 

Операторы приведения

Слово приведение используется в смысле «приведение к другому типу». В определенных ситуациях Java самостоятельно преобразует данные к другим типам. Например, если вещественной переменной присваивается целое значение, ком­пилятор автоматически выполняет соответствующее преобразование (int преобразуется во float). Приведение позволяет сделать замену типа более очевидной или выполнить ее принудительно в случаях, где это не происходит в обычном порядке.

Чтобы выполнить приведение явно, запишите необходимый тип данных (включая все модификаторы) в круглых скобках слева от преобразуемого значения. Пример:

//: operators/Casting.java

public class Casting {

public static void main(String[] args) {

int i = 200;

long lng = (long)i;

lng = i; // "Расширение", явное преобразование не обязательно

long lng2 = (long)200;

lng2 = 200;

// "Сужающее" преобразование:

i = (int)lng2; // Преобразование необходимо

}

}

Как видите, приведение может выполняться и для чисел, и для переменных. Впрочем, в указанных примерах приведение является излишним, поскольку компилятор при необходимости автоматически преобразует целое int к типу long. Однако это не мешает вам выполнять необязательные приведения — например, чтобы подчеркнуть какое-то обстоятельство или просто для того, чтобы сделать программу более понятной. В других ситуациях приведение может быть необходимо для нормальной компиляции программы.

В C и C++ приведение могло стать источником ошибок и неоднозначности. В Java приведение безопасно, за одним исключением: при выполнении так называемого сужающего приведения (то есть от типа данных, способного хранить больше информации, к менее содержательному типу данных), то есть при опасности потери данных. В таком случае компилятор заставляет вас выполнить явное приведение; фактически он говорит: «это может быть опасно, но, если вы уверены в своей правоте, опишите действие явно». В случае с расширяющим приведением явное описание не понадобится, так как новый тип данных способен хранить больше информации, чем прежний, и поэтому потеря данных исключена.

В Java разрешается приводить любой простейший тип данных к любому другому простейшему типу, но это не относится к типу boolean, который вообще не подлежит приведению. Классы также не поддерживают произвольное приведение. Чтобы преобразовать один класс в другой, требуются специальные методы. (Как будет показано позднее, объекты можно преобразовывать в рамках семейства типов; объект Дуб можно преобразовать в Дерево и наоборот, но не к постороннему типу вроде Камня.)

 

Округление и усечение

При выполнении сужающих преобразований необходимо обращать внимание на усечение и округление данных. Например, как должен действовать компилятор Java при преобразовании вещественного числа в целое? Скажем, если значение 29.7 приводится к типу int, что получится — 29 или 30 ?

Ответ на этот вопрос может дать следующий пример:

//: operators/CastingNumbers.java

// Что происходит при приведении типов

// float или double к целочисленным значениям?

import static net.mindview.util.Print.*;

 

public class CastingNumbers {

public static void main(String[] args) {

double above = 0.7, below = 0.4;

float fabove = 0.7f, fbelow = 0.4f;

print("(int)above: " + (int)above);

print("(int)below: " + (int)below);

print("(int)fabove: " + (int)fabove);

print("(int)fbelow: " + (int)fbelow);

}

}

<spoiler text="Output:">

(int)above: 0

(int)below: 0

(int)fabove: 0

(int)fbelow: 0

</spoiler> Отсюда и ответ на наш вопрос — приведение от типов с повышенной точностью double и float к целочисленным значениям всегда осуществляется с усечением целой части. Если вы предпочитаете, чтобы результат округлялся, используйте метод round() изjava.lang.Math. Так как этот метод является частью java.lang, дополнительное импортирование не потребуется.

 

Повышение

Вы можете обнаружить, что при проведении любых математических и поразрядных операций примитивные типы данных, меньшие int (то есть char, byte и short), приводятся к типу int перед проведением операций, и получаемый результат имеет тип int. Поэтому, если вам снова понадобится присвоить его меньшему типу, придется использовать приведение. (И тогда возможна потеря информации.) В основном самый емкий тип данных, присутствующий в выражении, и определяет величину результата этого выражения; так, при перемноженииfloat и double результатом станет double, а при сложении long и int вы получите в результате long.

 

В Java отсутствует sizeof()

В C и C++ оператор sizeof() выдает количество байтов, выделенных для хранения данных. Главная причина для использования sizeof() — переносимость программы. Различным типам данных может отводиться различное количество памяти на разных компьютерах, поэтому для программиста важно определить размер этих типов перед проведением операций, зависящих от этих величин. Например, один компьютер выделяет под целые числа 32 бита, а другой — всего лишь 16 бит. В результате на первой машине программа может хранить в целочисленном представлении числа из большего диапазона. Конечно, аппаратная совместимость создает немало хлопот для программистов на C и C++. В Java оператор sizeof() не нужен, так как все типы данных имеют одинаковые размеры на всех машинах. Вам не нужно заботиться о переносимости на низком уровне — она встроена в язык.

 

Сводка операторов

Следующий пример показывает, какие примитивные типы данных используются с теми или иными операторами. Вообще-то это один и тот же пример, повторенный много раз, но для разных типов данных. Файл должен компилироваться без ошибок, поскольку все строки, содержащие неверные операции, предварены символами //! :

//: operators/AllOps.java

// Проверяет все операторы со всеми

// примитивными типами данных, чтобы показать,

// какие операции допускаются компилятором Java

 

public class AllOps {

// To accept the results of a boolean test:

void f(boolean b) {}

void boolTest(boolean x, boolean y) {

// Arithmetic operators:

//! x = x * y;

//! x = x / y;

//! x = x % y;

//! x = x + y;

//! x = x - y;

//! x++;

//! x--;

//! x = +y;

//! x = -y;

// Relational and logical:

//! f(x > y);

//! f(x >= y);

//! f(x < y);

//! f(x <= y);

f(x == y);

f(x != y);

f(!y);

x = x && y;

x = x || y;

// Bitwise operators:

//! x = ~y;

x = x & y;

x = x | y;

x = x ^ y;

//! x = x << 1;

//! x = x >> 1;

//! x = x >>> 1;

// Compound assignment:

//! x += y;

//! x -= y;

//! x *= y;

//! x /= y;

//! x %= y;

//! x <<= 1;

//! x >>= 1;

//! x >>>= 1;

x &= y;

x ^= y;

x |= y;

// Casting:

//! char c = (char)x;

//! byte b = (byte)x;

//! short s = (short)x;

//! int i = (int)x;

//! long l = (long)x;

//! float f = (float)x;

//! double d = (double)x;

}

void charTest(char x, char y) {

// Arithmetic operators:

x = (char)(x * y);

x = (char)(x / y);

x = (char)(x % y);

x = (char)(x + y);

x = (char)(x - y);

x++;

x--;

x = (char)+y;

x = (char)-y;

// Relational and logical:

f(x > y);

f(x >= y);

f(x < y);

f(x <= y);

f(x == y);

f(x != y);

//! f(!x);

//! f(x && y);

//! f(x || y);

// Bitwise operators:

x= (char)~y;

x = (char)(x & y);

x = (char)(x | y);

x = (char)(x ^ y);

x = (char)(x << 1);

x = (char)(x >> 1);

x = (char)(x >>> 1);

// Compound assignment:

x += y;

x -= y;

x *= y;

x /= y;

x %= y;

x <<= 1;

x >>= 1;

x >>>= 1;

x &= y;

x ^= y;

x |= y;

// Casting:

//! boolean bl = (boolean)x;

byte b = (byte)x;

short s = (short)x;

int i = (int)x;

long l = (long)x;

float f = (float)x;

double d = (double)x;

}

void byteTest(byte x, byte y) {

// Arithmetic operators:

x = (byte)(x* y);

x = (byte)(x / y);

x = (byte)(x % y);

x = (byte)(x + y);

x = (byte)(x - y);

x++;

x--;

x = (byte)+ y;

x = (byte)- y;

// Relational and logical:

f(x > y);

f(x >= y);

f(x < y);

f(x <= y);

f(x == y);

f(x != y);

//! f(!x);

//! f(x && y);

//! f(x || y);

// Bitwise operators:

x = (byte)~y;

x = (byte)(x & y);

x = (byte)(x | y);

x = (byte)(x ^ y);

x = (byte)(x << 1);

x = (byte)(x >> 1);

x = (byte)(x >>> 1);

// Compound assignment:

x += y;

x -= y;

x *= y;

x /= y;

x %= y;

x <<= 1;

x >>= 1;

x >>>= 1;

x &= y;

x ^= y;

x |= y;

// Casting:

//! boolean bl = (boolean)x;

char c = (char)x;

short s = (short)x;

int i = (int)x;

long l = (long)x;

float f = (float)x;

double d = (double)x;

}

void shortTest(short x, short y) {

// Arithmetic operators:

x = (short)(x * y);

x = (short)(x / y);

x = (short)(x % y);

x = (short)(x + y);

x = (short)(x - y);

x++;

x--;

x = (short)+y;

x = (short)-y;

// Relational and logical:

f(x > y);

f(x >= y);

f(x < y);

f(x <= y);

f(x == y);

f(x != y);

//! f(!x);

//! f(x && y);

//! f(x || y);

// Bitwise operators:

x = (short)~y;

x = (short)(x & y);

x = (short)(x | y);

x = (short)(x ^ y);

x = (short)(x << 1);

x = (short)(x >> 1);

x = (short)(x >>> 1);

// Compound assignment:

x += y;

x -= y;

x *= y;

x /= y;

x %= y;

x <<= 1;

x >>= 1;

x >>>= 1;

x &= y;

x ^= y;

x |= y;

// Casting:

//! boolean bl = (boolean)x;

char c = (char)x;

byte b = (byte)x;

int i = (int)x;

long l = (long)x;

float f = (float)x;

double d = (double)x;

}

void intTest(int x, int y) {

// Arithmetic operators:

x = x * y;

x = x / y;

x = x % y;

x = x + y;

x = x - y;

x++;

x--;

x = +y;

x = -y;

// Relational and logical:

f(x > y);

f(x >= y);

f(x < y);

f(x <= y);

f(x == y);

f(x != y);

//! f(!x);

//! f(x && y);

//! f(x || y);

// Bitwise operators:

x = ~y;

x = x & y;

x = x | y;

x = x ^ y;

x = x << 1;

x = x >> 1;

x = x >>> 1;

// Compound assignment:

x += y;

x -= y;

x *= y;

x /= y;

x %= y;

x <<= 1;

x >>= 1;

x >>>= 1;

x &= y;

x ^= y;

x |= y;

// Casting:

//! boolean bl = (boolean)x;

char c = (char)x;

byte b = (byte)x;

short s = (short)x;

long l = (long)x;

float f = (float)x;

double d = (double)x;

}

void longTest(long x, long y) {

// Arithmetic operators:

x = x * y;

x = x / y;

x = x % y;

x = x + y;

x = x - y;

x++;

x--;

x = +y;

x = -y;

// Relational and logical:

f(x > y);

f(x >= y);

f(x < y);

f(x <= y);

f(x == y);

f(x != y);

//! f(!x);

//! f(x && y);

//! f(x || y);

// Bitwise operators:

x = ~y;

x = x & y;

x = x | y;

x = x ^ y;

x = x << 1;

x = x >> 1;

x = x >>> 1;

// Compound assignment:

x += y;

x -= y;

x *= y;

x /= y;

x %= y;

x <<= 1;

x >>= 1;

x >>>= 1;

x &= y;

x ^= y;

x |= y;

// Casting:

//! boolean bl = (boolean)x;

char c = (char)x;

byte b = (byte)x;

short s = (short)x;

int i = (int)x;

float f = (float)x;

double d = (double)x;

}

void floatTest(float x, float y) {

// Arithmetic operators:

x = x * y;

x = x / y;

x = x % y;

x = x + y;

x = x - y;

x++;

x--;

x = +y;

x = -y;

// Relational and logical:

f(x > y);

f(x >= y);

f(x < y);

f(x <= y);

f(x == y);

f(x != y);

//! f(!x);

//! f(x && y);

//! f(x || y);

// Bitwise operators:

//! x = ~y;

//! x = x & y;

//! x = x | y;

//! x = x ^ y;

//! x = x << 1;

//! x = x >> 1;

//! x = x >>> 1;

// Compound assignment:

x += y;

x -= y;

x *= y;

x /= y;

x %= y;

//! x <<= 1;

//! x >>= 1;

//! x >>>= 1;

//! x &= y;

//! x ^= y;

//! x |= y;

// Casting:

//! boolean bl = (boolean)x;

char c = (char)x;

byte b = (byte)x;

short s = (short)x;

int i = (int)x;

long l = (long)x;

double d = (double)x;

}

void doubleTest(double x, double y) {

// Arithmetic operators:

x = x * y;

x = x / y;

x = x % y;

x = x + y;

x = x - y;

x++;

x--;

x = +y;

x = -y;

// Relational and logical:

f(x > y);

f(x >= y);

f(x < y);

f(x <= y);

f(x == y);

f(x != y);

//! f(!x);

//! f(x && y);

//! f(x || y);

// Bitwise operators:

//! x = ~y;

//! x = x & y;

//! x = x | y;

//! x = x ^ y;

//! x = x << 1;

//! x = x >> 1;

//! x = x >>> 1;

// Compound assignment:

x += y;

x -= y;

x *= y;

x /= y;

x %= y;

//! x <<= 1;

//! x >>= 1;

//! x >>>= 1;

//! x &= y;

//! x ^= y;

//! x |= y;

// Casting:

//! boolean bl = (boolean)x;

char c = (char)x;

byte b = (byte)x;

short s = (short)x;

int i = (int)x;

long l = (long)x;

float f = (float)x;

}

}

Заметьте, что действия с типом boolean довольно ограничены. Ему можно присвоить значение true или false, проверить на истинность или ложность, но нельзя добавить логические переменные к другим типам или произвести с ними любые иные операции.

В случае с типами char, byte и short можно заметить эффект повышения при использовании арифметических операторов. Любая арифметическая операция с этими типами дает результат типа int, который затем нужно явно приводить к изначальному типу (сужающее приведение, при котором возможна потеря информации). При использовании значений типа int приведение осуществлять не придется, потому что все значения уже имеют этот тип.

Однако не заблуждайтесь относительно безопасности происходящего. При перемножении двух достаточно больших целых чисел int произойдет переполнение. Следующий пример демонстрирует сказанное:

//: operators/Overflow.java

// Сюрприз! В Java можно получить переполнение.

public class Overflow {

public static void main(String[] args) {

int big = Integer.MAX_VALUE;

System.out.println("большое = " + big);

int bigger = big * 4;

System.out.println("еще больше = " + bigger);

}

}

<spoiler text="Output:">

большое = 2147483647

еще больше = -4

</spoiler> Компилятор не выдает никаких ошибок или предупреждений, и во время исполнения не возникнет исключений. Язык Java хорош, но хорош не настолько.

Совмещенное присваивание не требует приведения для типов char, byte, short, хотя для них и производится повышение, как и в случае с арифметическими операциями. С другой стороны, отсутствие приведения в таких случаях, несомненно, упрощает программу.

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

 

Резюме

Читатели с опытом работы на любом языке семейства C могли убедиться, что операторы Java почти нйчем не отличаются от классических. Если же материал этой главы показался трудным, обращайтесь к мультимедийной презентации «Thinking in C» (www.MindView.net).


 



<== предыдущая лекция | следующая лекция ==>
Поразрядные логические операторы | Глава 4 УПРАВЛЯЮЩИЕ КОНСТРУКЦИИ


Карта сайта Карта сайта укр


Уроки php mysql Программирование

Онлайн система счисления Калькулятор онлайн обычный Инженерный калькулятор онлайн Замена русских букв на английские для вебмастеров Замена русских букв на английские

Аппаратное и программное обеспечение Графика и компьютерная сфера Интегрированная геоинформационная система Интернет Компьютер Комплектующие компьютера Лекции Методы и средства измерений неэлектрических величин Обслуживание компьютерных и периферийных устройств Операционные системы Параллельное программирование Проектирование электронных средств Периферийные устройства Полезные ресурсы для программистов Программы для программистов Статьи для программистов Cтруктура и организация данных


 


Не нашли то, что искали? Google вам в помощь!

 
 

© life-prog.ru При использовании материалов прямая ссылка на сайт обязательна.

Генерация страницы за: 0.177 сек.