Что такое расширяющее преобразование типов
Расширяющее преобразование — это преобразование, при котором значение одного типа преобразуется в другой тип равного или большего размера. Сужающее преобразование — это преобразование, при котором значение одного типа преобразуется в другой тип меньшего размера. Таблицы в этом разделе описывают характеристики обоих типов преобразований.
Расширяющие преобразования
В следующей таблице описаны расширяющие преобразования, которые можно выполнять без потери данных.
Type | Можно без потери данных преобразовать в |
---|---|
Byte | UInt16, Int16, UInt32, Int32, UInt64, Int64, Single, Double, Decimal |
SByte | Int16, Int32, Int64, Single, Double, Decimal |
Int16 | Int32, Int64, Single, Double, Decimal |
UInt16 | UInt32, Int32, UInt64, Int64, Single, Double, Decimal |
Char | UInt16, UInt32, Int32, UInt64, Int64, Single, Double, Decimal |
Int32 | Int64, Double, Decimal |
UInt32 | Int64, UInt64, Double, Decimal |
Int64 | Decimal |
UInt64 | Decimal |
Single | Double |
Некоторые расширяющие преобразования к типу Single или Double могут привести к потере точности. В следующей таблице описаны расширяющие преобразования, которые могут привести к частичной потере данных.
Type | Можно преобразовать в |
---|---|
Int32 | Single |
UInt32 | Single |
Int64 | Single, Double |
UInt64 | Single, Double |
Decimal | Single, Double |
Сужающие преобразования
Приведение типов. Расширение и сужение
— Привет, Амиго! Тема сегодняшней лекции – расширение и сужение типов. С расширением и сужением примитивных типов ты познакомился уже давно. На 10 уровне. Сегодня мы расскажем, как это работает для ссылочных типов, т.е. для объектов классов.
Код | Описание |
---|---|
Тут мы видим три объявленных класса: животное, кот и тигр. Кот наследуется от Животного. А Тигр от Кота. | |
Объект класса Tiger всегда можно спокойно присвоить переменной с типом класса-родителя. Для класса Tiger – это Cat, Animal и Object. |
Теперь рассмотрим, что же такое расширение и сужение типов.
Если в результате присваивания мы двигаемся по цепочке наследования вверх (к типу Object), то это — расширение типа (оно же — восходящее преобразование или upcasting), а если вниз, к типу объекта, то это — сужение типа (оно же — нисходящее преобразование или downcasting).
Движение вверх по цепочке наследования называется расширением, поскольку оно приводит к более общему типу. Но при этом теряется возможность вызвать методы, которые были добавлены в класс при наследовании.
Код | Описание |
---|---|
При сужении типа, нужно использовать оператор преобразования типа, то есть мы выполняем явное преобразование. При этом Java-машина выполняет проверку, а действительно ли данный объект унаследован от Типа, к которому мы хотим его преобразовать. Преобразование и приведение примитивных типов в JavaИногда возникают ситуации, когда необходимо переменной одного типа присвоить значение переменной другого типа. Например: 1. Автоматическое преобразование типов JavaРассмотрим сначала автоматическое преобразование. Если оба типа совместимы, их преобразование будет выполнено в Java автоматически. Например, значение типа byte всегда можно присвоить переменной типа int, как это показано в предыдущем примере. Для автоматического преобразования типа должно выполняться два условия: В этом случае происходит преобразование с расширением. Следующая схема показывает расширяющее преобразование в Java: Сплошные линии обозначают преобразования, выполняемые без потери данных. Штриховые линии говорят о том, что при преобразовании может произойти потеря точности. 2. Приведение типов Javaгде параметр целевой_тип обозначает тип, в который нужно преобразовать указанное значение. Например, в следующем фрагменте кода тип int приводится к типу byte : Рассмотрим пример преобразования значений с плавающей точкой в целые числа. В этом примере дробная часть значения с плавающей точкой просто отбрасывается (операция усечения): При приведении более емкого целого типа к менее емкому старшие биты просто отбрасываются: При приведении более емкого значения с плавающей точкой в целое число происходит усечение и отбрасывание старших битов: 3. Автоматическое продвижение типов в выраженияхПомимо операций присваивания, определенное преобразование типов может выполняться и в выражениях. В языке Java действуют следующие правила: Следующий пример аналогичен предыдущему, но используется операция совмещенного присваивание, в которой приведение происходит автоматически: 8.2 – Продвижение целочисленных типов и типов с плавающей запятойВ уроке «4.3 – Размеры объектов и оператор sizeof » мы отметили, что в C++ есть гарантии минимального размера для каждого из базовых типов. Однако фактический размер этих типов может варьироваться в зависимости от компилятора и архитектуры. Напоминание Количество бит, которое использует тип данных, называется его шириной. Более широкий тип данных – это тот, который использует больше битов, а более узкий тип данных – тот, который использует меньше битов. Но что происходит, когда мы хотим, чтобы наш 32-битный процессор изменял 8-битное значение (например, символ) или 16-битное значение? Некоторые 32-битные процессоры (например, серия x86) могут напрямую манипулировать 8-битными и 16-битными значениями. Однако часто это происходит медленнее, чем манипулирование 32-битными значениями! Другие 32-разрядные процессоры (например, PowerPC) могут работать только с 32-разрядными значениями, и для манипулирования более узкими значениями необходимо использовать дополнительные приемы. Числовое продвижениеПоскольку C++ предназначен для портируемости и производительности в широком диапазоне архитектур, разработчики языка не хотели предполагать, что заданный CPU сможет эффективно манипулировать значениями, которые были уже, чем естественный размер данных для этого CPU. Чтобы помочь решить эту проблему, C++ определяет категорию преобразований типов, неофициально называемую числовым продвижением. Числовое продвижение (расширяющее преобразование типа) – это преобразование более узкого числового типа (например, char ) в более широкий числовой тип (обычно int или double ), который может быть эффективно обработан и с меньшей вероятностью приведет к переполнению. Все числовые продвижения сохраняют значения, что означает, что все значения в исходном типе могут быть представлены без потери данных или точности в новом типе. Поскольку такие продвижения безопасны, компилятор будет свободно использовать числовое продвижение по мере необходимости и при этом не будет выдавать предупреждение. Числовое продвижение снижает избыточностьЦифровое продвижение решает и другую проблему. Рассмотрим случай, когда вы хотели написать функцию для печати значения типа int : Здесь на помощь приходит числовое продвижение: мы можем писать функции с параметрами int и/или double (например, функция printInt() выше). Затем этот же код можно вызвать с аргументами типов, которые можно численно продвигать для совпадения с типами параметров функции. Категории числового продвиженияЧисловые правила продвижения делятся на две подкатегории: целочисленное продвижение и продвижение типов с плавающей запятой. Продвижение типов с плавающей запятойНачнем с более простого. Целочисленные продвиженияПравила целочисленного продвижения более сложны. Используя правила целочисленного продвижения, можно сделать следующие преобразования: Есть еще несколько других неотъемлемых правил продвижения, которые используются реже. Их можно найти по адресу Не все преобразования, сохраняющие значения, являются числовыми продвижениямиНекоторые преобразования типов с сохранением значений (например, int в long или int в double ) в C++ не считаются числовыми продвижениями (это числовые преобразования, которые мы вскоре рассмотрим в уроке «8.3 – Числовые преобразования»). Различие носит в основном академический характер. Однако в некоторых случаях компилятор предпочитает числовые продвижения числовым преобразованиям. Мы увидим примеры, в которых это имеет значение, когда мы рассмотрим разрешение перегрузки функций (в следующем уроке «8.11 – Разрешение перегрузки функций и неоднозначные совпадения»). Что такое расширяющее преобразование типовКаждое выражение в Java имеет тип, который определяется структурой выражения и типами составляющих его операндов (констант, переменных и методов). Однако, иногда нам может потребоваться явное преобразование выражения в другой тип. Кроме того, в некоторых ситуациях исполняющая система Java сама неявно проводит такие преобразования. Преобразование типа Т1 в тип T2 позволяет выражению типа T1 трактоваться в период компиляции как выражение типа T2. В одних случаях это чисто синтаксическая конструкция, не влияющая на генерируемый код, в других преобразование типа требует дополнительных действий в период выполнения по изменению значения выражения или дополнительных проверок правильности применяемого преобразования. Примеры: Далее в этой главе приведена классификация всех возможных преобразований типов, а затем классификация контекстов в которой они могут использоваться. 5.4.1.1. Расширяющие преобразования чиселРасширяющие преобразования чисел это преобразования числового типа в «больший» числовой тип, которые считаются безопасными, т. к. не приводят к потере величины преобразуемого значения. Такими преобразованиями в Java являются: В действительности, преобразование целого значения в плавающее может привести к потере точности, т. е. к потере значащих цифр. Так, следующий пример 5.4.1.2. Сужающие преобразования чиселСужающие преобразования чисел это преобразования числового типа в «меньший» числовой тип, которые могут привести как к потере величины, так и к потере точности. Такими преобразованиями в Java являются: Мы не будем здесь подробно рассматривать правила, по которым происходят эти преобразования, поскольку интуитивно они понятны, а формально достаточно громоздки. При их применении важно помнить, что Java, в отличие от других языков, не генерирует ошибок при переполнении (overflow) или потере значения (underflow), поэтому контроль за корректностью преобразований полностью ложится на программиста. 5.4.1.3. Расширяющие преобразования ссылокРасширяющие преобразования ссылок это преобразования производных ссылочных типов в типы их предков, которые не требуют никаких действий на этапе исполнения и никогда не генерируют ошибок. Такими преобразованиями в Java являются: 5.4.1.4. Сужающие преобразования ссылокСужающие преобразования ссылок это преобразования производных ссылочных типов в типы их потомков. Эти преобразования требуют проверки своей легитимности на этапе исполнения и могут генерировать исключение ClassCastException. Такими преобразованиями в Java являются: 5.4.1.5. Преобразования в строкиЛюбое выражение в Java, включая null, может быть преобразовано в тип String. 5.4.1.6. Недопустимые преобразованияСледующие преобразования типов в Java запрещены: 5.4.2. Контексты преобразований5.4.2.1. Преобразование при присваиванииПреобразование при присваивании происходит, когда значение выражения присваивается переменной. При этом тип выражения преобразуется к типу переменной. При присваивании всегда возможны расширяющие преобразования типов (как числовых, так и ссылочных). Сужающее преобразование возможно только при соблюдении следующих условий: Например, оператор byte x = 123; допустим, поскольку константа 123 (имеющая тип int) лежит в диапазоне допустимых значений типа byte. Если тип выражения не может быть преобразован к типу переменной, то компилятор генерирует ошибку. В остальных случаях мы говорим, что тип выражения совместим по присваиванию с типом переменной. Так, следующий фрагмент приведет к генерации ошибки, поскольку типы char и short несовместимы по присваиванию согласно данных выше определениям (первый реализован 16-битовыми словами без знака, а второй со знаком). 5.4.2.2. Преобразование аргументов методаПреобразование аргументов метода происходит, когда фактические значения аргументов преобразуется к типу параметров метода или конструктора при его вызове. При этом всегда возможны расширяющие преобразования типов (как числовых, так и ссылочных) и недопустимы сужающие преобразования. Причины последнего запрета можно пояснить следующим примером: 5.4.2.3. Преобразование в строкуПреобразование в строку происходит только в одном случае: когда бинарная операция + применяется к двум операндам, один из которых имеет тип String. В этой ситуации второй операнд также преобразуется к типу String, и результатом операции является конкатенация полученных строк. Подробнее этот процесс описан в гл. 5.14. 5.4.2.4. Явное преобразование типаЯвное преобразование типа происходит, когда к операнду явно применяется операция приведения типа (type cast). В этой ситуации могут применяться все описанные выше виды преобразований типов, кроме преобразования в строку. Попытка явного преобразования к типу, отмеченная выше, как запрещенная, вызовет ошибку компиляции. Кроме того, на этапе выполнения возможна генерация исключения ClassCastException, если заданное преобразование недопустимо. 5.4.3. Преобразования типов числовых операндовПреобразование типов в процессе вычисления числовых выражений имеет ряд особенностей. Они сводятся к двум случаям: преобразования операндов в унарных операциях и в бинарных операциях. Перед выполнением унарной операции:
|