Преобразование типов

Открыта

— А теперь самое интересное. Я расскажу тебе про преобразование типов. Хоть типы переменных всегда неизменны, есть место, где можно проводить преобразование типов. И место это – присваивание.

— Можно присваивать друг другу переменные разных типов. При этом значение, взятое из переменной одного типа, будет преобразовано в значение другого типа и присвоено второй переменной.

— В связи с этим, можно выделить два вида преобразования типов: расширение и сужение. Расширение похоже на перекладывание из маленькой корзинки в большую – операция проходит незаметно и безболезненно. Сужение типа – это перекладывание из большой корзинки в маленькую: места может не хватить, и что-то придётся выбросить.

-Вот типы, отсортированные по размеру «корзинки»:

Преобразование типов - 1

— Тут есть пара замечаний:

1. char такая же корзинка, как и short, но свободно перекладывать из одной в другую нельзя: при перекладывании значения из short в char, всегда будут теряться значения меньше 0. При перекладывании из char в short будут теряться значения больше 32-х тысяч.

2. При преобразовании из целых чисел в дробные могут отбрасываться самые младшие части числа. Но т.к. смысл дробного числа в том, чтобы хранить приблизительное значение, то такое присваивание разрешается.

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

— Вот как нужно присваивать переменные разных типов:

Код на Java Описание
byte a = 115;
int b = a;
Расширение типа. Все отлично.
int c = 10000;
byte d = (byte) c;
Сужение типа. Нужно явно отбросить лишние байты.
int c = 10;
byte d = (byte) c;
Сужение типа. Нужно явно отбросить лишние байты, даже если они равны 0.
float f = 10000;
long l = (long) (f * f);
float f2 = l;
long l2 = (long) f2;
При присваивании к float, происходит расширение типа. При присваивании значения float к long, происходит сужение – необходимо приведение типа.
double d = 1;
float f = (float) d;
long l = (long) f;
int i = (int) l;
short s = (short) i;
byte b = (byte) s;
Сужение во всех операция присваивания, кроме первой строки, требует указания явного преобразования типа.
12
Задача
Java Syntax,  10 уровень,  3 лекция
Недоступна
Набираем код
Иногда думать не надо, строчить надо! Как ни парадоксально звучит, порой пальцы «запоминают» лучше, чем сознание. Вот почему во время обучения в секретном центре JavaRush вы иногда встречаете задания на набор кода. Набирая код, вы привыкаете к синтаксису и зарабатываете немного материи. А ещё — боретесь с ленью.

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

Код на Java Описание
float f = 10000;
long l = (long) f * f;
К типу long приводится только одна переменная из двух: умножение long и float дает float. Данный пример кода не будет скомпилирован.
float f = 10000;
long l = (long) (f * f);
Тут все выражение приводится к типу long. Этот пример кода будет скомпилирован.

— Ясно.

Комментарии (56)
  • популярные
  • новые
  • старые
Для того, чтобы оставить комментарий вы должны авторизоваться
Dmitry Potamoshnev19 уровень, Москва
9 июня, 08:44
Купил книгу "философия java", нашёл раздел про приведение типов и усечения.... В книге сплошная вода, чтобы все стало очевидно нужно чтобы кто-то разжевал. Спасибо JavaRush, что разжевали...
Vgoose14 уровень, Москва
26 мая, 14:25
Честно спёрто через гугл* При повышении типа byte>short; short>int; int>long; float>double; char>int информация не потеряется. При сужении возможна потеря информации. При различных операциях может происходить повышение типов в порядке «усиления» к более информативному типу. Например складывая int и double получим тип double. Но есть и особенность, например сложив double (8 байт) и long (8 байт) Java оставит знаки после запятой (double), а не более «длинный» тип. Кратко можно записать такие правила: 1. byte, short, char в выражениях всегда повышаются до int 2. если в выражении участвует тип long — то именно к этому типу будет приведён результат 3. если в выражении участвует float — то результат приводится к float 4. если один из операндов имеет тип double — то к этому типу будет приведён весь результат 5. При выборе между длиной и возможностью сохранить дробную часть — будет выбрана дробная часть
17 апреля, 10:54
При преобразовании из целых чисел в дробные могут отбрасываться самые младшие части числа. (c) что сие значит? Какие младшие разряды у целого числа........ или я что то не понимаю?
Майк10 уровень
24 мая, 15:56
++ 2. При преобразовании из целых чисел в дробные могут отбрасываться самые младшие части числа. Но т.к. смысл дробного числа в том, чтобы хранить приблизительное значение, то такое присваивание разрешается. Вот у нас есть целое число: 1000 Сделаем его дробным: 1000.0 Всё ок. Даже если, допустим, отбрасывать части числа (справа или особенно слева) то мы получаем весьма большую погрешность :/ Есть те кто понял?
Oleg Zaytsev24 уровень
6 марта, 11:22
нормальные лекции, к чему комментарии снизу непонятно
Alex13 уровень, Минск
8 февраля, 14:30
Расширение: Сужение: ****** Ниже стрелками на рисунке показано, какие преобразования типов могут выполняться автоматически. Пунктирными стрелками показаны автоматичекие преобразования с потерей точности.
DinosauR15 уровень, Киев
25 декабря 2018, 23:50
Вы прочитали, преобразование типов курильщика. а теперь почитайте: Преобразование типов нормального человека https://vertex-academy.com/tutorials/ru/prividenie-tipov-v-java/
Riccio28 уровень, Москва
5 января, 13:20
Спасибо, неплохой материал. Все тоже самое, но чуть другими словами - помогает лучше закрепить знания.
Шкипер16 уровень, Минск
29 марта, 13:16
Крутая статья.
Максим18 уровень
2 апреля, 07:02
Статья действительно полезная. Все четко и понятно. Хоть какое то прояснение в голове появилось )))
Stanislav Razumnik10 уровень, Санкт-Петербург
2 мая, 17:28
роскошная статья, благодарю
Радик28 уровень, Казань
29 ноября 2018, 19:33
Я не понимаю, почему если float f = 10000; long l = (long) (f * f); то float f2 = l; - без приведения типа Ведь float - 4 байта, long - 8 байт Если мы присваиваем long к переменной float f2, то мы сужаем тип, и надо указать (float), разве нет? Подскажите плиз.
IceBerg34 уровень, Днепр
4 декабря 2018, 14:09
Думаю long->float это автоматическое преобразование с потерей точности. Здесь все же расширение типа, ибо long попадет в диапазон значений float (хоть и имеем 8байт против 4-х), просто при таком вложении мы потеряем точность после 10+ знаков. В случае же сужения, например long в int, мы в результате рискуем получить совсем несуразное число, которое полностью не соответствует действительности. Пример long->float: long a = 123456789123456789L; float b = a; b = 123456789100000000.0; Пример long->int: long a = 123456789123456789L; int b = (int) a; b = -1395630315;
Асад18 уровень, Самара
16 октября 2018, 10:08
Кто нибудь может объяснить, почему при приведение
int c = 1000;
        byte d = (byte) c;
d=-24;
если
с =10000,
то
d =16;
я этот момент не могу понять
Макс26 уровень, Киев
2 ноября 2018, 09:42
Смотри, алгоритм приведения типа такой:
int c = 1000;
byte d = (byte) c;
/*
1000 - 128 = 872
872 - 128 = 744
744 - 128 = 616
616 - 128 = 488
488 - 128 = 360
360 - 128 = 232
232 - 128 = 104
104 - 128 = -24
*/
d = -24;
Санек10 уровень, Одесса
5 ноября 2018, 07:00
104 - 128 = -24
А чего не 104? Ведь попадает в диапазон.
Макс26 уровень, Киев
5 ноября 2018, 08:08
Как только число попало в диапазон, нужно ещё 1 раз отнять. Так уж устроено. Просто надо запомнить.
Anatoliy16 уровень
9 ноября 2018, 19:33
Правило интересное, но происходящее при сужении целых типов все-таки проще чем цепочка вычитаний. Для понимания сужения целых типов нужно помнить как компьютер хранит целые числа в виде байтов и битов, т.е. их двоичное представление. Переменные типа int четырехбайтные, т.е. каждая записывается тридцатью двумя ноликами и единичками. Например
int c = 1000;
будет записано в памяти так: 00000000 00000000 00000011 11101000 А
int c=10000;
так: 00000000 00000000 00100111 00010000 Переменные типа byte занимают в памяти один байт, т.е записываются восьмью ноликами и единичками. При сужении int к byte просто отбрасываются три старших байта. Т.е. в первом случае остается 11101000, а во втором 00010000 Со вторым числом все понятно, единственная единичка в четвертом разряде, 2^4 = 16. А вот почему первое -24? Потому, что все целые типы кроме char записаны в дополнительном коде. Про дополнительный код можно почитать, например, в Википедии: https://ru.wikipedia.org/wiki/Дополнительный_код Если не хочется вникать, достаточно запомнить два правила: 1. Если старший разряд числа равен нулю, то это число положительное и записано как обычное двоичное число (в десятичную переводится как сумма степеней двойки) 2. Если старший разряд числа равен единице, то число отрицательное и сразу его переводить в десятичную систему через сумму степеней двойки нельзя. Так вот, двоичная запись 11101000 соответствует числу -24 записанному в дополнительном коде. Вывод: получится ли при сужении к byte положительное или отрицательное число зависит только от значения седьмого двоичного разряда первоначального числа. PS. Если разделить число на 256, то остаток от деления как раз и будет равен младшему байту числа. Так что написанное у Шилдта на стр. 92 ничуть не противоречит сказанному выше.
Igor18 уровень, Санкт-Петербург
26 ноября 2018, 13:18
а почему тогда при int c = 10000; остается 16 , а не -112 ?
Riccio28 уровень, Москва
5 января, 13:25
А почему тогда бывают положительные числа в диапазоне?
Riccio28 уровень, Москва
5 января, 13:26
Если вам это все еще интересно, могу написать в личку как приводить числа. Потратил полдня чтобы в этом разобраться )))
Bo_Jackson14 уровень, Санкт-Петербург
8 марта, 11:40
мне интересно, посоветуйте статьи которые вам помогли, хочу тоже разобраться
Alex15 уровень, Одесса
17 мая, 12:56
Напишите и мне пожалуйста, интересно разобраться)
DancingShaman23 уровень
24 сентября 2018, 11:43
Не написано, что все строковые литералы по умолчанию преобразуются к одному общему типу int, это значит, что такой код выдаст ошибку: byte c = 10; byte m = 5; byte b = c + m; А чтобы ошибки не было, писать нужно так: byte b = (byte) c + m; Если в выражении есть хоть один строковый литерал типа long, то все литералы в выражении преобразются до long, если есть хоть один литерал типа char, то затем всё повышаются до char, тоже самое с double. Это дерьмо называются promotion rules. Вообще, читайте Шилдта, здесь теория слабая.
21 уровень, Москва
27 июня 2018, 16:10
ДЛЯ ТОГО ЧТО БЫ НЕ НАБИРАТЬ КОД МОЖНО ЕГО ПРОСТО ПЕРЕНЕСТИ, НЕ КОПИРОВАТЬ ПЕРЕНЕСТИ
2 августа 2018, 15:42
Так. И что значит перенести? И чем это отличается от скопировать?
Igor18 уровень, Киев
28 августа 2018, 18:31
Мишкой, что ли?
Марина27 уровень
4 сентября 2018, 09:42
Для того, чтобы не набирать ТУТ код, который просят, надо уже работать супер-пупер-мега программером и не сидеть ТУТ. Лень ли двигатель прогресса???