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

Открыта

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

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

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

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

Преобразование типов - 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.

— Ясно.

Комментарии (51)
  • популярные
  • новые
  • старые
Для того, чтобы оставить комментарий вы должны авторизоваться
позавчера, 10:54
При преобразовании из целых чисел в дробные могут отбрасываться самые младшие части числа. (c) что сие значит? Какие младшие разряды у целого числа........ или я что то не понимаю?
Oleg Zaytsev22 уровень
6 марта, 11:22
нормальные лекции, к чему комментарии снизу непонятно
Alex13 уровень, Минск
8 февраля, 14:30
Расширение: Сужение: ****** Ниже стрелками на рисунке показано, какие преобразования типов могут выполняться автоматически. Пунктирными стрелками показаны автоматичекие преобразования с потерей точности.
DinosauR15 уровень, Киев
25 декабря 2018, 23:50
Вы прочитали, преобразование типов курильщика. а теперь почитайте: Преобразование типов нормального человека https://vertex-academy.com/tutorials/ru/prividenie-tipov-v-java/
Riccio19 уровень, Москва
5 января, 13:20
Спасибо, неплохой материал. Все тоже самое, но чуть другими словами - помогает лучше закрепить знания.
Шкипер13 уровень, Минск
29 марта, 13:16
Крутая статья.
Максим14 уровень
2 апреля, 07:02
Статья действительно полезная. Все четко и понятно. Хоть какое то прояснение в голове появилось )))
Радик26 уровень, Казань
29 ноября 2018, 19:33
Я не понимаю, почему если float f = 10000; long l = (long) (f * f); то float f2 = l; - без приведения типа Ведь float - 4 байта, long - 8 байт Если мы присваиваем long к переменной float f2, то мы сужаем тип, и надо указать (float), разве нет? Подскажите плиз.
IceBerg31 уровень, Днепр
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;
я этот момент не могу понять
Макс20 уровень, Киев
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? Ведь попадает в диапазон.
Макс20 уровень, Киев
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 ?
Riccio19 уровень, Москва
5 января, 13:25
А почему тогда бывают положительные числа в диапазоне?
Riccio19 уровень, Москва
5 января, 13:26
Если вам это все еще интересно, могу написать в личку как приводить числа. Потратил полдня чтобы в этом разобраться )))
Bo_Jackson14 уровень, Санкт-Петербург
8 марта, 11:40
мне интересно, посоветуйте статьи которые вам помогли, хочу тоже разобраться
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
Мишкой, что ли?
Марина25 уровень
4 сентября 2018, 09:42
Для того, чтобы не набирать ТУТ код, который просят, надо уже работать супер-пупер-мега программером и не сидеть ТУТ. Лень ли двигатель прогресса???
Артем18 уровень
19 октября 2017, 08:01
Так ошибок не выдает
float f = 10000;
long l = (long) (f * f);
или
float f = 10000;
long l = (long) f * (long) f;
Джонни35 уровень
8 октября 2017, 14:28
Этот код не компиллируется.
float f = 10000;
long l = (long) f * f;
Ошибка: Error:(13, 27) java: incompatible types: possible lossy conversion from float to long
Logikarma35 уровень, Санкт-Петербург
5 декабря 2017, 18:09
Он и не должен, написано же, что результат выражения (справа от знака равно) будет под типом float. Значит приведения типов в этом выражении нет.
Джонни35 уровень
5 декабря 2017, 21:09
Судя по лекции результат должен быть float. "К типу long приводится только одна переменная из двух: умножение long и float дает float."
Ollie18 уровень
8 января 2018, 06:32
Так тебе компилятор и говорит, что возможно сужение. Ты в long пытаешься занести float.
Джонни35 уровень
8 января 2018, 07:16
Так где ошибка? В лекции, получается?
Beslan Bavizhev39 уровень
20 января 2018, 22:20
В лекции нет ошибки. В правой части выражения ты явно привел к long первый f, второй f остался float. В итоге результат вычисления правой части выражения (long * float) дает float. Соответственно, long`у в левой части не присвоишь этот float без явного приведения к long. Поэтому и не компилируется.
Джонни35 уровень
22 января 2018, 02:45
Видимо, не дописали, что так делать нельзя :)