• ,

Уровень 10: план уровня и доп. материалы

План уровня:
  • Приведение примитивных типов: расширение и сужение.
  • Примитивные типы
  • Преобразование типов. Расширение и сужение типов
  • Особенности преобразования типов
  • instanceof
  • Литералы

Курс Java

Что еще можно посмотреть на досуге:
Расширение и сужение типов в Java
Модификатор final
Маленькие хитрости в Java

study-java.ru/uroki-java/urok-7-preobrazovanie-tipov-v-java/#chartoint

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


Нашли классную ссылку к материалу данной темы? Добавьте ее сюда в виде комментария.
Возможно, именно Ваша ссылка поможет другому человеку стать программистом и улучшить свою жизнь!

Вернуться к плану обучения

Вернуться к обучению java онлайн на JavaRush

59 комментариев

Tristan
Отличные ссылки на материал, спасибо!
Walmar
Объясните, пожалуйста, почему при таком прелбраховании:
int a = 257;
        int b = 4;
        int c = 3;
        int e = 2;
        double d = (byte) a + b/c/e;


Выдаёт 1.0? Понятно, что это число выходит за значения byte, но почему 1.0 ?!
SergeyKandalintsev
b/c/e даст 0. Надеюсь это понятно?

257 в двоичной системе это 100000001. Тип int в Java это 32 бита или 4 байта. В памяти компьютера число 257 будет храниться как
00000000 00000000 00000001 00000001. При сужении этого значения до типа byte три старших байта будет откинута и мы получим 00000001. Далее к этому значению прибавляем 0 типа int (четыре нулевых байта) и получаем 1 типа int(нули в трех старших байтах, в младшем байте везде нули кроме 1 в самом младшем бите). При присвоении результата переменной d происходит расширение типа ind до double. Вот и получается, что d будет хранить еденичку типа double.
Alex1
int a = -129;
int b = (byte)a;
b равно 127
Ощущение что идет перезапись по кругу, т.е. 256 значений, из них 128 отрицательных и 127 положительных включая 0.
SergeyKandalintsev
Отрицательные целые хранятся в дополнительном коде. -129int это:
11111111 11111111 11111111 01111111
При приведении к byte 3 старших байта теряются. Остается 01111111(2) --> 127(10). Перед присвоением b происходит преобразование в int путем добавления 3-х нулевых байт. В результате b будет равна 127.
Mati
Спасибо, Сергей! Очень круто объясняете! Самые понятные объяснения на тему приведения типов!
YuraVel
  • YuraVel
  • 0
  • Комментарий отредактирован 2016-03-14 18:11:34 пользователем YuraVel
А при приведении числа 129, как происходит выше сказанное преобразование? 00000000 00000000 0000000 10000001?????????????? Будем производить инвертирование и прибавить единицу?????
SergeyKandalintsev
Не понял вопрос. В переменной какого типа храниться 129 и какие действия производятся?
Invictus
Тоже долго не мог понять. В итоге нашел механизм приведения в byte не прибегая к переводу в двоичную систему. Дело в том, что если преобразуемое число выходит за границы значений byte (-128...127), то результатом присвоения будет остаток деления по модулю приводимого числа на диапазон значений byte (256). Т.е. в примере выше, 257 = 256*1 + 1, Эта единица и будет выведена. Для числа 666 например, 666 = 256*3 — 102, т.е. будет выведено -102.
PetroRulov
int a = ...// любое целое число
if(a >= 256) a = a % 256;
if(a <= 127)
{
return a;
}
return a % 128 — 128;
SoulsHunter
Объясните пожалуйста про char.Честно рылась в интернете, но такое впечатление, то там всем все понятно. Вот пример из найденного который отражает мое понимание: «В языке Java, как и во многих языках программирования, строка представляет собой объект. Даже одиночный символ, взятый в кавычки (напрмер, „а“), является строкой. В Java предусмотрен более простой тип для одиночных символов — char.
Символы в Java заключаются в одинарные кавычки (например, 'a'). Операции, допустимые для символов:
присвоение;
сравнение;
объединение в строки.»

Но как с ними можно производить арифметические действия?? Объясните пожалуйста.
Groomsh
Все довольно просто, Char это примитив, как и int, со значением от 0 до 65536.
Грубо говоря, представь просто, что за каждым символом скрывается свой номер, который ты просто не видишь. Когда ты сравниваешь char'ы, сравниваются их номера.
Почитай про Unicode.
Например разница между строчным и прописным символом = 32.
serfer
а 32 == 'пробел' )))
chowee
интересно, а кто-нибудь читает вообще лекции?)
chowee
мне было странно узнать, что char в java 2 байта занимает, а не 1, как в си.
но я уже нагуглил эту тему — оказывается и 2 байта для char уже устарело и юникод требует 4 байта.
как дальше жить?..
serfer
будет 3 мировая. Перебьют пару наций и снова будет влазить в 2 байта)
Munch
public int getCost() {
int cost = super.getCost();
if (getNumber() > DISCOUNT_NUMBER) {
cost *= (1 — percentDiscount / 100);
}
return cost;
}

percentDiscount — double

кто-нибудь может пояснить, почему так работает и почему это лучше, чем явное приведение?
darkstone
Действительно интересно, найти нигде не нашёл, но думаю дело в операторе *=
Скорее всего в его реализации прописано что-то такое:
x *= y; -> (тип)x = (тип)x * (тип)y;

то есть в реализации приводят второй оператор к типу первого.
Munch
Интересно все таки узнать реализацию, чтобы понять как на самом деле. Оно понятно, что собака в "*=" зарыта.
darkstone
ну это и есть в принципе реализация

A compound assignment operator has the following syntax:

<variable> <op>= <expression>


and the following semantics:

<variable> = (<type>) (<variable> <op> (<expression>))
Munch
Спасибо. Мне бы еще ссылочку на первоисточник.
darkstone
Первоисточника нету, так бы привёл. Выдрал из stackowerflow. Там ссылку тоже не привели.
Munch
Пнятно.
darkstone
  • darkstone
  • 0
  • Комментарий отредактирован 2014-03-14 16:02:31 пользователем darkstone
ой, то есть конечно
x *= y; -> (тип)x = (тип)(x * y);
hubert
  • hubert
  • +1
  • Комментарий отредактирован 2014-03-14 17:13:10 пользователем hubert
eugeniuskh
все хорошо в этом курсе. Но такие ссылки значительно тормозят обучение тем, кто в английском не очень силен. Например, мне(
Kest
Объясните пожалуйста как float на 4 байтах может хранить больше чем long на 8 байтах

10^127 vs. 10^18
Спасибо
igor
погугли про представление чисел с плавающей точкой.
ToxyGenn
Меня больше смущает каким образом в этот список попал Object?
Судя по спецификации, его тут быть не должно
docs.oracle.com/javase/specs/jls/se7/html/jls-4.html#jls-4.2
blacky
Все что описано про статическую типизацию, как правильно делать приведения, диапазоны, спецификация и т.п. — это все замечательно, но необходимо знать где и в каких случаях эти типы данных использовать.
В книжке Джошуа Блоха 2002 `Java. Эффективное программирование` есть статья посвященная этой теме «31 Если требуются точные ответы, избегайте использования типов float и double». Вот кусок:
Типы float и double в первую очередь предназначены для научных и инженерных расчетов. Они реализуют бинарную арифметику с плавающей точкой (binary floating-point arithmetic), которая была тщательно выстроена с тем, чтобы быстро получать правильное приближение для широкого диапазона значений. Однако эти типы не дают точного результата, и в ряде случаев их нельзя использовать. Типы float и double — нe подходят для денежных расчетов, поскольку с их помощью невозможно представить число 0.1 (или любую другую отрицательную степень числа десять).
Например, у вас в кармане лежит $1.03, и вы тратите 42 цента. Сколько денег у вас осталось? Приведем фрагмент наивной программы, которая пытается ответить на этот вопрос:
System.out.println(1.03 — .42);
Как ни печально, программа выводит 0.6100000000000001. И это не единственный случай. Предположим, что у вас в кармане есть доллар, и вы покупаете девять прокладок для крана по десять центов за каждую. Какую сдачу вы получите?
System.out.println(1.00 — 9*.10);
Если верить этому фрагменту программы, то вы получите $0.09999999999999995.

Правильный путь решения задачи заключается в применении для денежных расчетов типов BigDecimal, int или long.
Про модификатор final тоже очень интересно — если он присутствует в исходном коде, то при изменении этого значения придется все зависимые классы перекомпилить, иначе останется старое значение.
Ruzveld
в уроке «Литералы» написано, что 0.256 — литерал типа float. Вроде там double должно быть. Или я не прав?
antonchar
  • antonchar
  • 0
  • Комментарий отредактирован 2014-06-29 12:33:16 пользователем antonchar
Меня тоже смутило

Floating-Point Literals

A floating-point literal is of type float if it ends with the letter F or f; otherwise its type is double and it can optionally end with the letter D or d.

The floating point types (float and double) can also be expressed using E or e (for scientific notation), F or f (32-bit float literal) and D or d (64-bit double literal; this is the default and by convention is omitted).

double d1 = 123.4;
// same value as d1, but in scientific notation
double d2 = 1.234e2;
float f1  = 123.4f;

Primitive Data Types
ToxyGenn
  • ToxyGenn
  • 0
  • Комментарий отредактирован 2014-08-27 20:05:08 пользователем ToxyGenn
Да, похоже на ошибку.
<code>Object o = 123.2;
System.out.println(o.getClass());</code>
Результат:
class java.lang.Double
ToxyGenn
Еще смутил момент:

Но ведь можно сделать приведение одной из переменных к float. Выглядеть будет лучше на мой взгляд:
int a = 3; int b = 5;
float f = (float) a / b;
ToxyGenn
Да, действительно глупость написал.
eNdiD
Так и не понял, в чем глупость.
float f = (float) a / b;

Код нормально работает. Что не так?
dyu
  • dyu
  • 0
Интересно, по какой версии Java делал свой курс Вязовик
old.intuit.ru/department/pl/javapl/7/3.html
оно же
www.intuit.ru/studies/courses/16/16/lecture/484?page=3
Меня смутило в главе 7 о приведении типов подпункт о присвоении значений в следующей части:
«Например, примитивные значения нельзя присваивать объектным переменным, включая следующие примеры:…
// приведение к классу-»обертке"
// также запрещено
Long a=5L;"

В Java 7 данный пример отработал нормально. Или я что-то не понял.
ferasinka
Эта лекция была написана еще в 2003-м году: www.chtivo.ru/book/508278/
А версия Java 5.0 с автоупаковкой и автораспаковкой вышла только через год, так что та лекция уже устарела
dyu
Нда, спасибо.
Но в целом материал подан хорошо и большинство вещей вполне себе фундаментальные.
Просто теперь буду чаще перепроверять и ставить под сомнение.
South
В таблице из лекции указано, что тип boolean занимает 1 байт памяти. Но это же не так, он занимает 4 байта (32 бита) памяти, как и int.
Исправьте что-ли.
Bolja
Оба варианта верны. 4 байта boolean занимает в переменных, 1 байт — в массивах.
South
Спасибо! не знала насчёт размера boolean в массивах.
Grimarr
study-java.ru/uroki-java/urok-7-preobrazovanie-tipov-v-java/#chartoint вот тут отлично расписаны примеры преобразования типов
Nara
  • Nara
  • 0
Ребята, помогите понять следующий момент. «Переменной Object можно присвоить ссылку любого типа (расширение типа). Но чтобы выполнить обратное присваивание (сужение типа) приходится явно указывать операцию приведения».

Почему так? Ведь при наследовании дочерний класс получает поля и методы родительского + определяет свои. Разве дочерний класс не шире родительского? Следуя этой логике – всё должно быть наоборот: присваивание родительского объекта дочернему является расширением, а дочернего родительскому — сужение. Где я не так понял?
South
При наследовании мы расширяем родительский класс полями и методами дочернего класса. Но именно из-за этого дочерний класс становится более специализированным, более узким и более конкретным, чем родительский.

Вспомним зоологию — родительский класс — Млекопитающие. Это животные, которые вскармливают детенышей молоком и покрыто шерстью (кто-то в большей степени, кто-то в меньшей). Дочерним классом к нему являются Хищники. Добавляются методы: «Питаются мясом», «Охотятся». С одной стороны Хищники расширяют Млекопитающих этими методами, но с другой стороны — это более узкая группа по отношению к Млекопитающим.
lexel
Не могу понять как происходит механизм преобразования например с int в byte.

int a = 250;
byte b = (byte) a;
System.out.println(b);

результат будет -6.
Каким образом 250 преобразовалось в -6?
desiq
int a = 250; < — 11111010
byte b = (byte) a; < — при приведении получаем дополнительный код со старшим битом 1 т.е отрицательное число — вычитаем 1 = 11111001 и инвертируем, получаем 00000110 = 6
System.out.println(b); < — -6
lexel
Каким образом происходит это приведение? Из лекций я знаю что в byte может быть число входящее в диапазон -128… 127. То число 250 в этот диапазон не попадает. И его нужно как-то уменьшить до этого диапазона.
Мне видно не хватает знаний по поводу операций с двоичным кодом.
int a = 250; < — 11111010
как перевести 250 в двоичный код я еще могу понять
128 64 32 16 8 4 2 1
 1   1  1  1 1 0 1 1

Т.е. если сложить все суммы, под которыми стоят единички, то получится 250. Соответственно это и будет в двоичной системе.
а вот дальше я не понимаю
при приведении получаем дополнительный код со старшим битом 1 т.е отрицательное число — вычитаем 1

если долго писать то можете скинуть ссылку где почитать? А то я даже не знаю что искать в Google
desiq
  • desiq
  • 0
  • Комментарий отредактирован 2016-01-06 11:34:25 пользователем desiq
почитай про перевод отрицательных чисел в двоичную систему(прямой и дополнительный код) вот тут например
lexel
Я нашел формулу, используя которую можно узнать сколько будет int в byte без перевода в двоичный код.
Диапазон byte -128...127
Таким образом весь диапазон это 256 ( 128 + 127 и плюс 1 (ноль тоже учитывается)
И теперь чтобы перевести любое int число, которое выходит за рамки -128...127 нужно просто отнимать от этого числа 256 пока оно не войдет в этот диапазон.
Пример:
Для примера возьмем число 500
500 — 256 = 244
244 — 256 = -12
(int) 500 = (byte) -12
Но про двоичный код так же стоит почитать и разобраться.
Вот еще полезная на мой взгляд ссылка
mrANDERSON
Манти́сса пишется с двумя «сс» :)
mrANDERSON
Это 2я лекция, если что)
mrANDERSON
  • mrANDERSON
  • 0
  • Комментарий отредактирован 2016-01-17 18:58:29 пользователем mrANDERSON
Уважаемые разработчики курса, все-так int — это от -2(в 31) до 2(в 31) — 1, а long — -2(в 63)…2(в 63)-1.
Т.е. 2*10(в 9) это 2_000_000, int же = 2147483647 (см. Integer.MAX_VALUE); тоже и с long.
Если я не прав — поправьте кто-нибудь, пожалуйста!
snuk
По двоичному коду доступным языком-здесь. Конвертер двоичногл кода в десятичный и обратно(надо потестировать, разбираясь в двоичке)-тут. Непонятный по статьям момент сужения чара к байту и наоборот — тут.
dioxide
А зачем на boolean выделять целый байт?
Yuri_0504
Потому что в памяти все хранится в байтах, поэтому создавать примитивы меньше байта не имеет смысла.
Nullptr
Спасибо за ссылки. Про рыбу и селедку порадовало. :)
Paulus123
мне понравился этот ресурс с табличками
pr0java.blogspot.com/2015/12/java.html
Только зарегистрированные и авторизованные пользователи могут оставлять комментарии.