Какие данные мы рискуем потерять при явных приведениях
Перейти к содержимому

Какие данные мы рискуем потерять при явных приведениях

  • автор:

Объектно-ориентированное программирование

127
-128
-128
Видно, что знаковый бит при сужении не оказал никакого влияния, так как был просто отброшен – результат приведения обратных чисел (384, -384) оказался одинаковым. Следовательно, может быть потеряно не только точное абсолютное значение, но и знак величины.
Это верно и для char:

-25536
Преобразование ссылочных типов (расширение и сужение)
Преобразование объектных типов лучше всего иллюстрируется с помощью дерева наследования. Рассмотрим небольшой пример наследования:

В каждом классе объявлено поле с уникальным именем. Будем рассматривать это поле как пример набора уникальных свойств, присущи некоторому объектному типу.
Объекты класса Parent обладают только одним полем x, а значит, только ссылки типа Parent могут ссылаться на такие объекты. Объекты класса ChildY обладают полем y и полем x, полученным по наследству от класса Parent. Стало быть, на такие объекты могут указывать ссылки типа ChildY или Parent. Пример:

Parent p = new ChildY();

Обратите внимание, что с помощью такой ссылки p можно обращаться лишь к полю x созданного объекта. Поле y недоступно, так как компилятор, проверяя корректность выражения p.y, не может предугадать, что ссылка p будет указывать на объект типа ChildY во время исполнения программы. Он анализирует лишь тип самой переменной, а она объявлена как Parent, но в этом классе нет поля y, что и вызовет ошибку компиляции.
Аналогично, объекты класса ChildZ обладают полем z и полем x, полученным по наследству от класса Parent. Значит, на такие объекты могут указывать ссылки типа ChildZ и Parent.
Таким образом, ссылки типа Parent могут указать на объект любого из трех рассматриваемых типов, а ссылки типа ChildY и ChildZ – только на объекты точно такого же типа. Теперь можно перейти к преобразования ссылочных типов на основе такого дерева наследования.
Расширение означает переход от более конкретного типа к менее конкретному, т.е. переход от детей к родителям. Подобно случаю с примитивными типами, этот переход производиться самой JVM при необходимости и «незаметен» для разработчика, то есть не требует никаких специальных преобразования.

Parent p1=new ChildY();
Parent p2=new ChildZ();

В обеих строках переменным типа Parent присваивается значение другого типа, а значит, происходит преобразование. Поскольку это расширение, оно производиться автоматически и всегда успешно.
Нужно заметить, что при подобном преобразовании с самим объектом ничего не происходит. Несмотря на то что, например, поле y класса ChildY теперь недоступно, это не значит, что оно исчезло. Такое существенно изменение объекта не возможно. Он был порожден от класса ChildY и сохраняет все его свойства. Изменился лишь тип ссылки, через которую идет обращение к объекту.
Обратный переход, то есть движение по дереву наследования вниз, к наследникам, является сужением. Например, для рассматриваемого случая, переход от ссылки типа Parent , которая может ссылаться на объекты трех классов, к ссылке типа ChildY, которая может ссылаться только на один класс из трех, очевидно, является сужением. Такой переход может оказаться невозможным. Если ссылка типа Parent ссылается на объект типа Parent или ChildZ, то переход к ChildY невозможен, так как в обоих случаях объект не обладает полем y, которое объявлено в классе ChildY. Поэтому при сужении разработчику необходимо явным образом указывать на то, что необходимо попытаться провести такое преобразование. JVM во время исполнения проверит корректность перехода. Если он возможен, преобразование будет проведено. Если же нет – возникнет ошибка (обычно ClassCastException).

Parent p=new ChildY();
ChildY cy = (ChildY)p; //верно
Parent p2=new ChildZ();
ChildY cy2 = (ChildY)p2; //ошибка

Чтобы проверить, возможен ли желаемый переход, можно воспользоваться оператором instanceof:

Parent p=new ChildY();
if (p instanceof ChildY) <
ChildY cy = (ChildY)p;
>

Parent p2=new ChildZ();
if (p2 instanceof ChildY) <
ChildY cy = (ChildY)p2;
>

Parent p3=new Parent();
if (p3 instanceof ChildY) <
ChildY cy = (ChildY)p3;
>

  • Числовые типы записываются в текстовом виде без потери точности представления. Сначала на основе примитивного значения порождается экземпляр соответствующего класса-«обертки», затем у него вызывается метод toString(). Но поскольку эти действия снаружи незаметны, JVM оптимизирует их и преобразует примитивные значения в текст напрямую.
  • Булевские величины приводятся к строке «true» или «false» в зависимости от значения.
  • Для объектных величин вызывается метод toString(). Если метод возвращает null, то результатом будет строка “null”.
  • Для null-значения генерируется строка “null”.
  • Присвоение значений переменным (assignment). Не все переходы допустимы при таком преобразовании – ограничения выбраны таким образом, чтобы не могла возникнуть исключительная ситуация.
  • Вызов метода. Это преобразование применяется к аргументам вызываемого метода или конструктора. Такое приведение никогда не порождает ошибок. Так же приведение осуществляется при возвращении значения метода.
  • Явное приведение. В этом случае явно указывается, к какому типу требуется привести исходное значение.
  • Оператор конкатенации производит преобразование к строке своих аргументов.
  • Числовое расширение. Числовые операции могут потребовать изменения типа аргумента(ов). Это преобразование имеет особое название – расширенное, так как выбор целевого типа может зависеть не только от исходного значения, но и от второго аргумента операции.

posted by Sergey A Brazhnik at 09:38

2 Comments:

Это связано с тем, что char, в отличие от остальных целочисленных типов, является знаковым.

Может быть наоборот? Или тогда по-подробнее объясните пожалуйста.

Это приведение значений int к типу float и приведение значений типа long к типу float или double. Хотя эти дробные типы вмещают гораздо большие числа, чем соответствующие целые, но у них меньше значащих разрядов.

Непонятно, а пример приводится на сужение на самом деле

long a = 111111111111L;
float f=a;
a=(long)f; // () это как раз и есть операция преобразования типа
System.out.println(a); //результат 111111110656

Не понятно то что под заголовком «Применение приведений», особенно
числовое расширение и вызов метода. Нельзя ли по-подробнее, что имелось ввиду.
Заранее благодарю.

About

Блог учебных материалов по семинарам спец. курса ММФ НГУ «Объектно-ориентированное программирование» (автор Замулин А.В.).

Какие данные мы рискуем потерять при явных приведениях

Какие данные мы рискуем потерять при явных приведениях

Каждый базовый тип данных занимает определенное количество байт памяти. Это накладывает ограничение на операции, в которые вовлечены различные типы данных. Рассмотрим следующий пример:

В данном коде мы столкнемся с ошибкой. Хотя и тип byte, и тип int представляют целые числа. Более того, значение переменной a, которое присваивается переменной типа byte, вполне укладывается в диапазон значений для типа byte (от -128 до 127). Тем не менее мы сталкиваемся с ошибкой на этапе компиляции. Поскольку в данном случае мы пытаемся присвоить некоторые данные, которые занимают 4 байта, переменной, которая занимает всего один байт.

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

Операция преобразования типов предполагает указание в скобках того типа, к которому надо преобразовать значение. Например, в случае операции (byte)a , идет преобразование данных типа int в тип byte. В итоге мы получим значение типа byte.

Явные и неявные преобразования

Когда в одной операции вовлечены данные разных типов, не всегда необходимо использовать операцию преобразования типов. Некоторые виды преобразований выполняются неявно, автоматически.

Автоматические преобразования

Преобразования типов в языке Java

Стрелками на рисунке показано, какие преобразования типов могут выполняться автоматически. Пунктирными стрелками показаны автоматические преобразования с потерей точности.

Автоматически без каких-либо проблем производятся расширяющие преобразования (widening) — они расширяют представление объекта в памяти. Например:

В данном случае значение типа byte, которое занимает в памяти 1 байт, расширяется до типа int, которое занимает 4 байта.

Расширяющие автоматические преобразования представлены следующими цепочками:

byte -> short -> int -> long

short -> float -> double

Автоматические преобразования с потерей точности

Некоторые преобразования могут производиться автоматически между типами данных одинаковой разрядности или даже от типа данных с большей разрядностью к типа с меньшей разрядностью. Это следующие цепочки преобразований: int -> float , long -> float и long -> double . Они производятся без ошибок, но при преобразовании мы можем столкнуться с потерей информации.

Явные преобразования

Во всех остальных преобразованиях примитивных типов явным образом применяется операция преобразования типов. Обычно это сужающие преобразования (narrowing) от типа с большей разрядностью к типу с меньшей разрядностью:

Потеря данных при преобразовании

При применении явных преобразований мы можем столкнуться с потерей данных. Например, в следующем коде у нас не возникнет никаких проблем:

Число 5 вполне укладывается в диапазон значений типа byte, поэтому после преобразования переменная b будет равна 5. Но что будет в следующем случае:

Результатом будет число 2. В данном случае число 258 вне диапазона для типа byte (от -128 до 127), поэтому произойдет усечение значения. Почему результатом будет именно число 2?

Число a, которое равно 258, в двоичном системе будет равно 00000000 00000000 00000001 00000010 . Значения типа byte занимают в памяти только 8 бит. Поэтому двоичное представление числа int усекается до 8 правых разрядов, то есть 00000010 , что в десятичной системе дает число 2.

Усечение рациональных чисел до целых

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

Здесь значение числа b будет равно 56, несмотря на то, что число 57 было бы ближе к 56.9898. Чтобы избежать подобных казусов, надо применять функцию округления, которая есть в математической библиотеке Java:

Преобразования при операциях

Нередки ситуации, когда приходится применять различные операции, например, сложение и произведение, над значениями разных типов. Здесь также действуют некоторые правила:

если один из операндов операции относится к типу double , то и второй операнд преобразуется к типу double

если предыдущее условие не соблюдено, а один из операндов операции относится к типу float , то и второй операнд преобразуется к типу float

если предыдущие условия не соблюдены, один из операндов операции относится к типу long , то и второй операнд преобразуется к типу long

иначе все операнды операции преобразуются к типу int

Так как в операции участвует значение типа double, то и другое значение приводится к типу double и сумма двух значений a+b будет представлять тип double.

Две переменных типа byte и short (не double, float или long), поэтому при сложении они преобразуются к типу int , и их сумма a+b представляет значение типа int. Поэтому если затем мы присваиваем эту сумму переменной типа byte, то нам опять надо сделать преобразование типов к byte.

Pro Java

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

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

Преобразование типов в Java бывает двух видов: неявное и явное.

Неявное преобразование типов выполняется в случае если выполняются условия:

  1. Оба типа совместимы
  2. Длина целевого типа больше или равна длине исходного типа

JavaBasics_ImplicitTypeCastingPrimitives

Во всех остальных случаях должно использоваться явное преобразование типов.

Так же существуют два типа преобразований:

  1. Расширяющее преобразование (widening conversion)
  2. Сужающее преобразование (narrowing conversion)

Расширяющее преобразование (widening conversion) происходит, если значение одного типа преобразовывается в более широкий тип, с большим диапазоном допустимых значений. Java выполняет расширяющие преобразования автоматически, например, если вы присвоили литерал типа int переменной типа double или значение пепременной типа char переменной типа int. Неявное преобразование всегда имеет расширяющий тип .

GrabliНо у тут могут быть свои небольшие грабельки. Например если преобразуется значение int в значение типа float. И у значения int в двоичном представлении больше чем 23 значащих бита, то возможна потеря точности, так как у типа float под целую часть отведено 23 бита. Все младшие биты значения int, которые не поместятся в 23 бита мантиссы float, будут отброшены, поэтому хотя порядок числа сохраниться, но точность будет утеряна. То же самое справедливо для преобразования типа long в тип double.

Расширяющее преобразование типов Java можно изобразить еще так:

JavaBasics_ImplicitTypeCastingPrimitivesDetailed

Сплошные линии обозначают преобразования, выполняемые без потери данных. Штриховые линии говорят о том, что при преобразовании может произойти потеря точности.

Стоит немного пояснить почему, к примеру тип byte не преобразуется автоматически (не явно) в тип char, хотя тип byte имеет ширину 8 бит, а char 16, тоже самое касается и преобразования типа short в char. Это происходит потому, что byte и short знаковые типы данных, а char без знаковый. Поэтому в данном случае требуется использовать явное приведение типов, поскольку компилятору надо явно указать что вы знаете чего хотите и как будет обрабатываться знаковый бит типов byte и short при преобразовании к типу char.

Поведение величины типа char в большинстве случаев совпадает с поведением величины целого типа, следовательно, значение типа char можно использовать везде, где требуются значения int или long. Однако напомним, что тип char не имеет знака, поэтому он ведет себя отлично от типа short, несмотря на то что диапазон обоих типов равен 16 бит.

short s = ( short ) 0xffff ; // Данные биты представляют число –1
char c = ‘\uffff’ ; // Те же биты представляют символ юникода
int i1 = s ; // Преобразование типа short в int дает –1
int i2 = c ; // Преобразование char в int дает 65535

Сужающее преобразование (narrowing conversion) происходит, если значение преобразуется в значение типа, диапазон которого не шире изначального. Сужающие преобразования не всегда безопасны: например, преобразование целого значения 13 в byte имеет смысл, а преобразование 13000 в byte неразумно, поскольку byte может хранить только числа от −128 до 127. Поскольку во время сужающего преобразования могут быть потеряны данные, Java компилятор возражает против любого такого преобразования, даже если преобразуемое значение укладывается в более узкий диапазон указанного типа:

int i = 13 ;
byte b = i ; // Компилятор не разрешит это выражение

Единственное исключение из правила – присвоение целого литерала (значения типа int) переменной byte или short, если литерал соответствует диапазону переменной.

Сужающее преобразование это всегда явное преобразование типов .

Явное преобразование примитивных типов

Оператором явного преобразования типов или точнее говоря приведения типов являются круглые скобки, внутри которых указан тип, к которому происходит преобразование – (type). Например:

int i = 13 ;
byte b = ( byte ) i ; // Принудительное преобразование int в byte
i = ( int ) 13.456 ; // Принудительное преобразование литерала типа double в int 13

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

При приведении более емкого целого типа к менее емкому старшие биты просто отбрасываются . По существу это равнозначно операции деления по модулю приводимого значения на диапазон целевого типа (например для типа byte это 256).

Слишком большое дробное число при приведении к целому превращается в MAX_VALUE или MIN_VALUE .

Слишком большой double при приведении к float превращается в Float.POSITIVE_INFINITY или Float.NEGATIVE_INFINITY .

Таблица представленная ниже представляет собой сетку, где для каждого примитивного типа указаны типы, в которые их можно преобразовать, и способ преобразования. Буква N в таблице означает невозможность преобразования. Буква Y означает расширяющее преобразование, которое выполняется автоматически. Буква С означает сужающее преобразование, требующее явного приведения. Наконец, Y* означает автоматическое расширяющее преобразование, в процессе которого значение может потерять некоторые из наименее значимых разрядов. Это может произойти при преобразовании int или long во float или double. Типы с плавающей точкой имеют больший диапазон, чем целые типы, поэтому int или long можно представить посредством float или double. Однако типы с плавающей точкой являются приближенными числами и не всегда могут содержать так много значащих разрядов в мантиссе, как целые типы.

JavaBasics_ImplicitTypeCastingPrimitivesDetailedTable

Автоматическое расширение типов в выражениях

Так же стоит еще раз упомянуть об автоматическом повышении (расширении) типов в выражениях. Мы с этим уже сталкивались когда рассматривали целочисленные типы данных и операции над ними, но все же стоит и тут напомнить, чтобы усвоилось еще лучше и к тому же это имеет непосредственное отношение к данной теме. В примере ниже знак @ означает любой допустимый оператор, например +, , *, / и т.п.

С0001

То есть, все целочисленные литералы в выражениях, а так же типы byte, short и char расширяются до int . Если, как описано выше, в выражении не присутствуют другие, более большие типы данных (long, float или double). Поэтому приведенный выше пример вызовет ошибку компиляции, так как переменная c имеет тип byte, а выражение b+1, в результате автоматического повышения имеет тип int.

Неявное приведение типов в выражениях совмещенного присваивания

Хоть данный раздел и относится к неявному преобразованию (приведению) типов, его объяснение мы привели тут, поскольку в данном случае так же работает и автоматическое расширение типов в выражениях, а затем уже неявное приведение типов. Вот такой кордебалет. Пример ниже я думаю все разъяснит. Так же как и в предыдущем объяснении знак @ означает любой допустимый оператор, например +, , *, / и т.п.

С0002

Это стоит пояснить на простом примере:

byte b2 = 50 ;
b2 = b2 * 2 ; // не скомпилируется
b2 *= 2 ; //скомпилируется, хотя и равнозначна b2 = b2 * 2

Вторя строка, приведенная в примере не скомпилируется из-за автоматического расширения типов в выражениях, так как выражение b2*2 имеет тип int, так как происходит автоматическое расширение типа (целочисленные литералы в выражении всегда int). Третья же строка спокойно скомпилируется, так как в ней сработает неявное приведение типов в совмещенном выражении присваивания.

Boxing/unboxing – преобразование примитивных типов в объекты обертки

Boxing и unboxin – это тоже достаточно большая тема, но она достаточно простая.

По существу boxing и unboxing это преобразование примитивных типов в объекты обертки и обратно .

Для объектов оберток примитивных типов применимо все что было сказано выше.

Об классах обертках упоминалось в таблицах, при разборе каждого из примитивных типов. Но тогда это было лишь упоминание в таблице.

Так вот, для каждого примитивного типа есть его старший брат, и он совсем не примитивный, а является настоящим классом, с полями и методами. И для каждой такой парочки возможно автоматическое преобразование.

С0003

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

Приведу простой пример:

int i3 ;
byte b2 = 3 ;
Byte myB ;
myB = b2 ;
myB ++;
b2 = myB ;
i3 = myB ;

Если пока не понятно зачем это нужно, то это не страшно, просто завяжите узелок на память.

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

Преобразование типов — это тема, которая может показаться сложной начинающим программировать на Java. Однако, заверим Вас, на самом деле всё просто. Главное понять по каким законам происходит взаимодействие между переменными и помнить об этом при написании программ. Итак, давайте разбираться.

В Java существует 2 типа преобразований — картинка Вам в помощь:

preobrazovaniya-v-java_vertex-academy

Напомним, что вся «Вселенная Java» состоит из:

  • примитивных типов (byte, short, int, long, char, float, double, boolean)
  • объектов

В данной статье мы:

  • рассмотрим преобразование типов для примитивных типов переменных
  • преобразование объектов (String, Scanner и др.) в этой статье не рассматривается, поскольку с объектами происходит отдельная «магия» — это тема для отдельной статьи.
Автоматическое преобразование

Ну, что ж, давайте попробуем разобраться что такое «автоматическое преобразование».

Помните, когда мы рассматривали типы переменных (в статье «Переменные в Java. Создание переменной»), мы говорили, что переменная — это некоторый «контейнер» , в котором может храниться значение для дальнейшего использования в программе. Также мы говорили о том, что каждый тип переменной имеет свой диапазон допустимых значений и объем занимаемой памяти. Вот она табличка, где это все было расписано:

variables-java_vertex-academy

Так вот, к чему мы, собственно говоря, клоним. К тому, что совсем не просто так Вам давались диапазоны допустимых значений и объем занимаемой памяти ��

Давайте, сравним, например:

1. byte и short. byte имеет меньший диапазон допустимых значений, чем short. То есть byte это как бы коробочка поменьше, а short — это коробочка побольше. И значит, мы можем byte вложить в short.

2. byte и int . byte имеет меньший диапазон допустимых значений, чем int. То есть byte это как бы коробочка поменьше, а int — это коробочка побольше. И значит, мы можем byte вложить в int.

3. int и long. int имеет меньший диапазон допустимых значений, чем long. То есть int это как бы коробочка поменьше, а long — это коробочка побольше. И значит, мы можем int вложить в long.

avtomaticheskoe-preobrazovanie_1_vertex-academy

Это и есть пример автоматического преобразования. Это можно схематически изобразить в виде вот такой картинки:

avtomaticheskoe-preobrazovanie-v-java_vertex-academy

Давайте рассмотрим как это работает на практике.

Пример №1

Код №1 — если Вы запустите это код на своем компьютере, в консоли будет выведено число 15

Saved searches

Use saved searches to filter your results more quickly

You signed in with another tab or window. Reload to refresh your session. You signed out in another tab or window. Reload to refresh your session. You switched accounts on another tab or window. Reload to refresh your session.

Вопросы и ответы для подготовки к интервью и прохождения Ревью на JavaMentor

mihmosi/JavaInterwiewQuestions

Name already in use

  • Local
  • Codespaces

Use Git or checkout with SVN using the web URL.

Work fast with our official CLI. Learn more about the CLI.

Sign In Required

Please sign in to use Codespaces.

Launching GitHub Desktop

If nothing happens, download GitHub Desktop and try again.

Launching GitHub Desktop

If nothing happens, download GitHub Desktop and try again.

Launching Xcode

If nothing happens, download Xcode and try again.

Launching Visual Studio Code

Your codespace will open once ready.

There was a problem preparing your codespace, please try again.

Latest commit

Git stats

Files

Failed to load latest commit information.

README.md

Вопросы и ответы для подготовки к интервью и прохождения Ревью на JavaMentor

Теоретические вопросы для повторения:

Все примитивные типы и их размеры

Потери при неявных приведениях возможны потери точности при преобразовании целочисленных в вещественные а именно из long -> float

Что такое Autoboxing, unboxing и когда они происходят автоматически?
Процесс преобразования примитивных типов в ссылочные (int->Integer) называется autoboxing (автоупаковкой), а обратный ему — unboxing (автораспаковкой). Классы-обертки являются immutable (неизменяемыми): это означает, что после создания объекта его состояние — значение поля value — не может быть изменено. Классы-обертки задекларированы как final: объекты, так сказать, read-only. Также хотелось бы упомянуть, что от этих классов невозможно наследоваться. Java автоматически делает преобразования между примитивными типами и их обертками:

Какая размерность у boolean? 1. В стандартной реализации Sun JVM и Oracle HotSpot JVM тип boolean занимает 4 байта (32 бита), как и тип int. Однако, в определенных версиях JVM имеются реализации, где в массиве boolean каждое значение занимает по 1-му биту.

Переведи число X (любое) из десятичной в двоичную, и число Y (любое) из двоичной в десятичную https://calculatori.ru/perevod-chisel.html Любое число может быть легко переведено в десятичную систему по следующему алгоритму: Каждая цифра числа должна быть умножена на основание системы счисления этого числа возведенное в степень равное позиции текущей цифры в числе справа налево, причём счёт начинается с 0. степени 2-ки 3 2 1 0 1 1 1 1 ==
222 + 2*2 + 2 +1

Какие классы-обертки знаешь? byte Byte short Short
int Integer long Long char Character float Float double Double boolean Boolean https://javarush.ru/groups/posts/1948-objertki-raspakovka-i-zapakovka Обертка — это специальный класс, который хранит внутри себя значение примитива. Но поскольку это именно класс, он может создавать свои экземпляры. Они будут хранить внутри нужные значения примитивов,
при этом будут являться настоящими объектами http://java-online.ru/java-lang-wrapper.xhtml

Расскажи про pool строк и pool примитивов Для более эффективного использования памяти в java используются так называемые пулы. Есть строковый пул, Integer пул и т.д. Когда мы создаем объект не используя new, он помещается в пул и в полседствии, если мы захотим создать такой же объект (не используя new) новый не будет создан а мы просто получим ссылку из пула. Особенность Integer-пула — он хранит только числа, которые помещаются в топ данных byte от — 128 до 127 . Для остальных пул не работает.

Разница между String, StringBuilder и StringBuffer? Объекты String являются неизменяемыми, поэтому все операции, которые изменяют строки, фактически приводят к созданию новой строки, что сказывается на производительности приложения. Для решения этой проблемы, чтобы работа со строками проходила с меньшими издержками в Java были добавлены классы StringBuffer и StringBuilder. По сути они напоминает расширяемую строку, которую можно изменять без ущерба для производительности.

Эти классы похожи, практически двойники, они имеют одинаковые конструкторы, одни и те же методы, которые одинаково используются. Единственное их различие состоит в том, что класс StringBuffer синхронизированный и потокобезопасный. То есть класс StringBuffer удобнее использовать в многопоточных приложениях, где объект данного класса может меняться в различных потоках. Если же речь о многопоточных приложениях не идет, то лучше использовать класс StringBuilder, который не потокобезопасный, но при этом работает быстрее, чем StringBuffer в однопоточных приложениях можно все делать со строкой но потом вернуть строку через метод: .toString();

Какая максимальная длина массива? Теоретически максимальный размер массива будет Integer.MAX_VALUE. Практически это зависит от того, сколько памяти имеет ваш JVM и сколько из них уже выделено для других объектов.

Максимальная размерность многомерного массива

Почему 0.1 0.7 != 0.8 ? получим 0.7999999999999999

При сложении char short какой результирующий тип получим? Получим int Если в операциях участвуют данные типа char, то они преобразуются в int: int d = ‘a’ + 5; System.out.println(d); // 102

Отличие операторов сокращенных логических операторов и полных
полные операторы проверяют по умолчанию обе стороны выражения сокращенняые как && || — только одну, имеет большое значение при выполнении методов

Где находятся параметры и аргументы метода Обычно параметр является тем, что появляется в определении метода. Аргумент — это экземпляр, переданный методу во время выполнения.

Размер boolean-значенией в массиве типов boolean В стандартной реализации Sun JVM и Oracle HotSpot JVM тип boolean занимает 4 байта (32 бита), как и тип int. Однако, в определенных версия JVM имеются реализации, где в массиве boolean каждое значение занимает по 1-му биту.

Я полагаю, что это сделано как баланс между скоростью и удобством. То есть одиночный тип boolean рассматривается как int, а массив, рассматривается как массив byte, а кое где и вовсе как бит

Перевод 1111 в десятичную систему и обратно 15

Оператор XOR. Представить таблицу истинности для него True если хотя бы один true

Что такое явные и неявные приведения, с чем связано их наличие? Каждый базовый тип данных занимает определенное количество байт памяти. Это накладывает ограничение на операции, в которые вовлечены различные типы данных.

Автоматически без каких-либо проблем производятся расширяющие преобразования (widening)

  • они расширяют представление объекта в памяти. Например: byte b = 7; int d = b; // преобразование от byte к int В данном случае значение типа byte, которое занимает в памяти 1 байт, расширяется до типа int, которое занимает 4 байта.

Расширяющие автоматические преобразования представлены следующими цепочками:

byte -> short -> int -> long int -> double short -> float -> double char -> int Автоматические преобразования с потерей точности

Некоторые преобразования могут производиться автоматически между типами данных одинаковой разрядности или даже от типа данных с большей разрядностью к типа с меньшей разрядностью. Это следующие цепочки преобразований: int -> float, long -> float и long -> double. Они производятся без ошибок, но при преобразовании мы можем столкнуться с потерей информации.

int a = 2147483647; float b = a; // от типа int к типу float System.out.println(b); // 2.14748365E9

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

если один из операндов операции относится к типу double, то и второй операнд преобразуется к типу double

если предыдущее условие не соблюдено, а один из операндов операции относится к типу float, то и второй операнд преобразуется к типу float

если предыдущие условия не соблюдены, один из операндов операции относится к типу long, то и второй операнд преобразуется к типу long

иначе все операнды операции преобразуются к типу int

Какие данные мы рискуем потерять при явных приведениях? при явно преобразовании необходимо учитывать разрядность числа и наличие знаков после запятой

Логические операторы. & end | or ^ xor ! not

Что такое char? Почему над ним можно выполнять арифметические операции? Имеет целочисленное неотрицательное значение 16 bit от 0 до Представляет номер символа в системе Unicode Чтобы получить код символа, достаточно выполнить приведение к типу int: char ch = ‘n’; System.out.println((int)ch);

Неизменяемые типы String, типы-Обертки, от них нельзя наследовться можно сделать свойнеизменяемый класс

  1. ссылочные поля копировать через клон
  2. поля должны быть private и finale
  3. задаваться значения только через конструктор
  4. только сеттеры
  5. класс должен быть тоже finale

Почему не рекомендуются множественные конкатенации String? Больше Затрат по памяти и времени

чем отличается метод от функции? ничем

можно ли положить максимальное значение long во float можно с потерей точности

byte a = 1; byte b = 2; byte c = a b; Будут ли какие-то проблемы? будет int или переполнение с явным преобразованием

Как добавить String’у в pool строк? использование оператора new заставляет класс String создать новый объект String. После этого можем использовать метод intern(), чтобы поместить этот объект в пул строк или обратиться к другому объекту из пула строк, который имеет такое же значение.

Что такое массив и какие на нём есть ограничения?

Расскажи про все условные операторы? while (true) < ..>; do <. >while(true); if(true) < ..>if() < ..>else if () < >switch(.) < case: .. break; >;

Отличия for от for each цикл for -это конструкция, которая говорит: «выполните эту операцию n раз «.

или foreach используется для перебора каждого элемента заданного набора или списка (все, что реализует IEnumerable ) предопределенным образом. Вы не можете повлиять на точный порядок (кроме пропуска записей или отмены всего цикла), поскольку это определяется контейнером.

а for -это просто еще один способ написать цикл, код которого выполняется перед входом в цикл и один раз после каждой итерации. Обычно он используется для циклического перебора кода заданное количество раз. В отличие от foreach
здесь вы можете влиять на текущую позицию.

  1. Потеря данных при преобразовании short/char тип byte не преобразуется автоматически (не явно) в тип char, хотя тип byte имеет ширину 8 бит, а char — 16. То же самое касается и преобразования типа short в char. Это происходит потому, что byte и short знаковые типы данных, а char беззнаковый. Поэтому в данном случае требуется использовать явное приведение типов, поскольку компилятору надо явно указать, что вы знаете чего хотите и как будет обрабатываться знаковый бит типов byte и short при преобразовании к типу char.

Инкременты, декременты, отличия.

Пулы строк и integer

Что такое рекурсия? Недостатки и преимущества?

2 случая (правила/условия) в рекурсивном алгоритме?

Какие могут быть потери данных при явных привидениях?

Double to int произойет потеря значений после запятой без округления

Continue \ break
Оператор continue позволяет перейти к следующей итерации цикла до завершения выполнения всех инструкций внутри цикла. В качестве примера выведем все числа от 1 до 100, кроме чисел от 5 до 10 включительно

Оператор break позволяет прервать выполнение цикла досрочно. Для примера вы- ведем все числа от 1 до 100 еще одним способом: int i = 1; while (true) < if (i > 100) break; System.out.println(i); i++; >Здесь мы в условии указали значение true. В этом случае инструкции внутри цикла будут выполняться бесконечно. Однако использование оператора break прерывает его выполнение, как только 100 строк уже напечатано.
ВНИМАНИЕ! Оператор break прерывает выполнение цикла, а не программы, т. е. далее будет вы- полнена инструкция, следующая сразу за циклом. Бесконечный цикл совместно с оператором break удобно использовать для получе- ния неопределенного заранее количества данных от пользователя. В качестве при- мера просуммируем неопределенное количество целых чисел (листинг 3.8).

  1. ради интереса — размер объекта оберток и прочих

Дополнительные темы (выпишите себе ответы в отдельный файл) Вещественные числа: Большие числа BigInteger и BigDecimal

Преобразование с потерями в Java

В этом кратком руководстве мы обсудим концепцию преобразования с потерями в Java и причину этого.

В то же время мы рассмотрим некоторые удобные методы преобразования, чтобы избежать этой ошибки.

2. Преобразование С Потерями

Преобразование с потерями-это просто потеря информации при обработке данных.

В Java это соответствует возможности потери значения или точности переменной при преобразовании одного типа в другой.

Когда мы пытаемся назначить переменную типа большого размера типу меньшего размера , Java генерирует ошибку, несовместимые типы: возможное преобразование с потерями , при компиляции кода.

Например, давайте попробуем назначить long для int :

Java выдаст ошибку при компиляции этого кода:

Здесь Java найдет long и int несовместимыми и приведет к ошибке преобразования с потерями. Потому что могут быть длинные значения за пределами int диапазона от -2,147,483,648 до 2,147,483,647.

Аналогично, давайте попробуем назначить float a long :

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

Аналогично, присвоение double номера int приведет к той же ошибке:

Значения double могут быть слишком большими или слишком маленькими для int , и десятичные значения будут потеряны при преобразовании. Следовательно, это потенциальное преобразование с потерями.

Кроме того, мы можем столкнуться с этой ошибкой при выполнении простого вычисления:

Когда double умножается на int , мы получаем результат в double . Следовательно, это также потенциальное преобразование с потерями.

Поэтому несовместимые типы в преобразовании с потерями могут иметь разные размеры или типы (целые или десятичные числа).

3. Примитивные Типы данных

В Java существует множество примитивных типов данных, доступных с соответствующими классами-оболочками .

Далее давайте составим удобный список всех возможных преобразований с потерями в Java:

  • short to byte или char
  • char to байт или короткий
  • int to byte , short или char
  • long to byte , short , char или int
  • float to byte , short , char , int или long
  • double to byte , short , char , int , long или float

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

4. Методы преобразования

4.1. Преобразование Между Примитивными Типами

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

Например, давайте преобразуем длинное число в короткое с помощью понижающей передачи :

Аналогично, давайте преобразуем double в int :

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

Давайте преобразуем длинные значения за пределами диапазона короткие :

Если мы внимательно проанализируем конверсию, то увидим, что это не ожидаемые значения.

Другими словами, когда Java достигает наибольшего значения типа малого размера при преобразовании из типа большого размера, следующее число является наименьшим значением типа малого размера и наоборот.

Давайте разберемся в этом на примерах. Когда большое длинное число со значением 32768 преобразуется в короткое , значение короткое число 1 равно -32768 . Поскольку максимальное значение short равно 32767, поэтому Java переходит к следующему минимальному значению short.

Аналогично, когда маленькое длинное число преобразуется в короткое . Значение short Num2 равно 32767, поскольку Java переходит к следующему максимальному значению short .

Кроме того, давайте посмотрим, что произойдет, когда мы преобразуем максимальные и минимальные значения a long в int :

4.2. Преобразование между объектами-оболочками и примитивными типами

Чтобы напрямую преобразовать объект-оболочку в примитив, мы можем использовать различные методы в классах-оболочках, такие как int Value () , shortValue() и longValue() . Это называется распаковка .

Например, давайте преобразуем объект Float в объект long :

Кроме того, если мы посмотрим на реализацию long Value или аналогичных методов, мы найдем применение сужающего примитивного преобразования:

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

После преобразования значение long Num будет равно 15. Однако двойное число равно 15.9999, что очень близко к 16.

Вместо этого мы можем использовать Math.round() для преобразования в ближайшее целое число:

4.3. Преобразование Между Объектами-Оболочками

Для этого давайте воспользуемся уже рассмотренными методами преобразования.

Сначала мы преобразуем объект-оболочку в примитивное значение, опустим его и преобразуем в другой объект-оболочку . Другими словами, мы будем выполнять техники распаковки, даункастинга и бокса.

Например, давайте преобразуем объект Double в объект Integer :

Наконец, мы используем Integer . valueOf() для преобразования примитивного типа int в Целое число объект. Этот тип преобразования называется boxing .

5. Заключение

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

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

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

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *