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

Каждый базовый тип данных занимает определенное количество байт памяти. Это накладывает ограничение на операции, в которые вовлечены различные типы данных. Рассмотрим следующий пример:
int a = 4; byte b = a; // ! Ошибка
В данном коде мы столкнемся с ошибкой. Хотя и тип byte, и тип int представляют целые числа. Более того, значение переменной a,
которое присваивается переменной типа byte, вполне укладывается в диапазон значений для типа byte (от -128 до 127). Тем не менее мы сталкиваемся с ошибкой на этапе
компиляции. Поскольку в данном случае мы пытаемся присвоить некоторые данные, которые занимают 4 байта, переменной, которая занимает всего один байт.
Тем не менее в программе может потребоваться, чтобы подобное преобразование было выполнено. В этом случае необходимо использовать операцию
преобразования типов (операция ()):
int a = 4; byte b = (byte)a; // преобразование типов: от типа int к типу byte System.out.println(b); // 4
Операция преобразования типов предполагает указание в скобках того типа, к которому надо преобразовать значение.
Например, в случае операции (byte)a, идет преобразование данных типа int в тип byte. В итоге мы получим значение типа byte.
Явные и неявные преобразования
Когда в одной операции вовлечены данные разных типов, не всегда необходимо использовать операцию преобразования типов.
Некоторые виды преобразований выполняются неявно, автоматически.
Автоматические преобразования
Стрелками на рисунке показано, какие преобразования типов могут выполняться автоматически. Пунктирными стрелками показаны автоматические преобразования
с потерей точности.
Автоматически без каких-либо проблем производятся расширяющие преобразования (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
Явные преобразования
Во всех остальных преобразованиях примитивных типов явным образом применяется операция преобразования типов. Обычно это сужающие преобразования (narrowing) от
типа с большей разрядностью к типу с меньшей разрядностью:
long a = 4; int b = (int) a;
Потеря данных при преобразовании
При применении явных преобразований мы можем столкнуться с потерей данных. Например, в следующем коде у нас не возникнет никаких проблем:
int a = 5; byte b = (byte) a; System.out.println(b); // 5
Число 5 вполне укладывается в диапазон значений типа byte, поэтому после преобразования переменная b будет равна 5. Но что будет в следующем случае:
int a = 258; byte b = (byte) a; System.out.println(b); // 2
Результатом будет число 2. В данном случае число 258 вне диапазона для типа byte (от -128 до 127), поэтому произойдет усечение значения. Почему результатом будет именно число 2?
Число a, которое равно 258, в двоичном системе будет равно 00000000 00000000 00000001 00000010.
Значения типа byte занимают в памяти только 8 бит. Поэтому двоичное представление числа int усекается до 8 правых разрядов, то есть 00000010,
что в десятичной системе дает число 2.
Усечение рациональных чисел до целых
При преобразовании значений с плавающей точкой к целочисленным значениям, происходит усечение дробной части:
double a = 56.9898; int b = (int)a;
Здесь значение числа b будет равно 56, несмотря на то, что число 57 было бы ближе к 56.9898. Чтобы избежать подобных казусов, надо применять
функцию округления, которая есть в математической библиотеке Java:
double a = 56.9898; int b = (int)Math.round(a);
Преобразования при операциях
Нередки ситуации, когда приходится применять различные операции, например, сложение и произведение, над значениями разных типов. Здесь также
действуют некоторые правила:
-
если один из операндов операции относится к типу
double, то и второй операнд преобразуется к типуdouble -
если предыдущее условие не соблюдено, а один из операндов операции относится к типу
float, то и второй операнд преобразуется к типуfloat -
если предыдущие условия не соблюдены, один из операндов операции относится к типу
long, то и второй операнд преобразуется к типуlong -
иначе все операнды операции преобразуются к типу
int
Примеры преобразований:
int a = 3; double b = 4.6; double c = a+b;
Так как в операции участвует значение типа double, то и другое значение приводится к типу double и сумма двух значений a+b будет
представлять тип double.
Другой пример:
byte a = 3; short b = 4; byte c = (byte)(a+b);
Две переменных типа byte и short (не double, float или long), поэтому при сложении они преобразуются к типу int, и их сумма
a+b представляет значение типа int. Поэтому если затем мы присваиваем эту сумму переменной типа byte, то нам опять надо сделать
преобразование типов к byte.
Если в операциях участвуют данные типа char, то они преобразуются в int:
int d = 'a' + 5; System.out.println(d); // 102
Данная статья:
- написана командой Vertex Academy. Надеемся, что она Вам будет полезна. Приятного прочтения!
- это одна из статей из нашего «Самоучителя по Java»
Преобразование типов — это тема, которая может показаться сложной начинающим программировать на Java. Однако, заверим Вас, на самом деле всё просто. Главное понять по каким законам происходит взаимодействие между переменными и помнить об этом при написании программ. Итак, давайте разбираться.
В Java существует 2 типа преобразований — картинка Вам в помощь:
Напомним, что вся «Вселенная Java» состоит из:
- примитивных типов (byte, short, int, long, char, float, double, boolean)
- объектов
В данной статье мы:
- рассмотрим преобразование типов для примитивных типов переменных
- преобразование объектов (String, Scanner и др.) в этой статье не рассматривается, поскольку с объектами происходит отдельная «магия» — это тема для отдельной статьи.
Автоматическое преобразование
Ну, что ж, давайте попробуем разобраться что такое «автоматическое преобразование».
Помните, когда мы рассматривали типы переменных (в статье «Переменные в Java. Создание переменной»), мы говорили, что переменная — это некоторый «контейнер», в котором может храниться значение для дальнейшего использования в программе. Также мы говорили о том, что каждый тип переменной имеет свой диапазон допустимых значений и объем занимаемой памяти. Вот она табличка, где это все было расписано:
Так вот, к чему мы, собственно говоря, клоним. К тому, что совсем не просто так Вам давались диапазоны допустимых значений и объем занимаемой памяти 🙂
Давайте, сравним, например:
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.
Это и есть пример автоматического преобразования. Это можно схематически изобразить в виде вот такой картинки:
Давайте рассмотрим как это работает на практике.
Пример №1
Код №1 — если Вы запустите это код на своем компьютере, в консоли будет выведено число 15
|
class Test { public static void main(String[] args) { byte a = 15; byte b = a; System.out.println(b); } } |
Код №2 — если Вы запустите это код на своем компьютере, в консоли будет выведено число 15
|
class Test { public static void main(String[] args) { byte a = 15; int b = a; System.out.println(b); } } |
И-и-и? Вы думаете, что раз в консоль было выведено одно и то же число, и код №1 отличается от кода №2 всего лишь типом переменной b, то между ними нет никакой разницы? Это не так.
В коде №2 присутствует автоматическое преобразование типов, а в коде №1 — нет:
Хотя число, в принципе, одно и то же, но теперь оно находится в большем контейнере, который занимает больше места на диске. При этом, JVM выполняет автоматические преобразования за Вас. Она знает, что int больше чем byte.
Приведение типов
Другое дело если вы пытаетесь переложить что-то из большего контейнера в более маленький.
Вы можете знать, что в большем контейнере лежит то, что поместиться и в маленьком – но об этом не знает JVM, и пытается предохранить вас от ошибок.
Поэтому, вы должны «прямо сказать», что ситуация под контролем:
|
class Test { public static void main(String[] args) { int a=0; long b=15; a = (int) b; } } |
Тут мы дописали (int) перед b. Если бы переменная a была, к примеру, типа byte, в скобках бы стояло (byte). Общая формула выглядит так:
Она говорит «сделай из (большего) значения b переменную нужного мне (целевого) типа int«.
Если что-то пошло не так.
До этого мы рассматривали ситуации, предполагая, что мы точно знаем, что делаем. Но что если попытаться поместить в контейнер то, что туда не помещается?
Оказывается, в контейнере останется лишь то, что туда «влезло». К примеру, у чисел с плавающей точкой будет «отсекаться» дробная часть:
|
//пример 1 class Test { public static void main(String[] args) { double a=11.2345; int b=(int)a; System.out.println(b); // в консоли получится число 11 } } |
Надо помнить, что дробная часть не округляется, а отбрасывается.
А что будет, если мы попытаемся поместить число, которое выходит за допустимые границы? Например, если в byte (диапазон byte от -128 до 127) положить число 128? Думаете, мы получим 1? Нет. Мы получим -128:
|
class Test { public static void main(String[] args) { double a=128; byte b=(byte)a; System.out.println(b); //в консоли увидим -128 } } |
Значение переменной при таком преобразовании можно рассчитать, но цель программиста – не допускать ситуации, когда значение выходит за допустимые границы, поскольку это может привести к неправильной работе программы.
Задания:
- Последовательно пропишите в компиляторе преобразования всех примитивных типов друг к другу, включая типы char и Составьте таблицу такого вида:
| byte | short | char | int | long | float | double | boolean | |
| byte | ||||||||
| short | ||||||||
| char | ||||||||
| int | ||||||||
| Long | ||||||||
| Float | ||||||||
| double | ||||||||
| boolean |
На пересечении напишите: а – если преобразование происходит автоматически, на – если нужно использовать явное преобразование, х – если преобразование невозможно.
* приведение типа к самому себе называется тождественным – его прописывать не обязательно
- Посмотрите еще раз, какой размер имеет каждый примитивный тип. Попытайтесь составить блок-схему, показывающую, куда помещаются какие типы. Проведите стрелочки с надписью «расширяющее преобразование» и «сужающее преобразование».
Вопросы
На собеседовании на должность Junior Java Developer Вас могут спросить:
Что Вы знаете о преобразовании примитивных типов данных, есть ли потеря данных, можно ли преобразовать логический тип?
Попробуйте ответить на вопрос.
Подытожим:
- Если Вы «кладёте» в больший контейнер содержимое меньшего контейнера», преобразование происходит автоматически, и ошибок возникать не должно.
- Если есть необходимость положить «значение из большего контейнера в меньший», нужно быть осторожным, и пользоваться явным приведением типов.
- При приведении float или double к целочисленным типам, дробная часть не округляется, а просто отбрасывается.
- Тип boolean не приводится ни к одному из типов.
- Тип char приводится к числовым типам, как код символа в системе UNICODE.
- Если число больше своего контейнера, результат будет непредсказуемым.
В этой статье описана только часть материала на тему приведения типов. Существуют также приведения объектных типов, приведение к строке (ведь в строке может быть записано все что угодно, правда?) и автоматическое продвижение типов в выражениях.
Надеемся, что наша статья была Вам полезна. Также есть возможность записаться на наши курсы по Java в Киеве. Обучаем с нуля. Детальную информацию Вы можете найти у нас на сайте.
Java provides various data types just likely any other dynamic languages such as boolean, char, int, unsigned int, signed int, float, double, long, etc in total providing 7 types where every datatype acquires different space while storing in memory. When you assign a value of one data type to another, the two types might not be compatible with each other. If the data types are compatible, then Java will perform the conversion automatically known as Automatic Type Conversion, and if not then they need to be cast or converted explicitly. For example, assigning an int value to a long variable.
| Datatype | Bits Acquired In Memory |
|---|---|
| boolean | 1 |
| byte | 8 (1 byte) |
| char | 16 (2 bytes) |
| short | 16(2 bytes) |
| int | 32 (4 bytes) |
| long | 64 (8 bytes) |
| float | 32 (4 bytes) |
| double | 64 (8 bytes) |
Widening or Automatic Type Conversion
Widening conversion takes place when two data types are automatically converted. This happens when:
- The two data types are compatible.
- When we assign a value of a smaller data type to a bigger data type.
For Example, in java, the numeric data types are compatible with each other but no automatic conversion is supported from numeric type to char or boolean. Also, char and boolean are not compatible with each other.
Example:
Java
class GFG {
public static void main(String[] args)
{
int i = 100;
long l = i;
float f = l;
System.out.println("Int value " + i);
System.out.println("Long value " + l);
System.out.println("Float value " + f);
}
}
Output
Int value 100 Long value 100 Float value 100.0
Narrowing or Explicit Conversion
If we want to assign a value of a larger data type to a smaller data type we perform explicit type casting or narrowing.
- This is useful for incompatible data types where automatic conversion cannot be done.
- Here, the target type specifies the desired type to convert the specified value to.
char and number are not compatible with each other. Let’s see when we try to convert one into another.
Java
public class GFG {
public static void main(String[] argv)
{
char ch = 'c';
int num = 88;
ch = num;
}
}
Output: An error will be generated
This error is generated as an integer variable takes 4 bytes while character datatype requires 2 bytes. We are trying to plot data from 4 bytes into 2 bytes which is not possible.
How to do Explicit Conversion?
Java
public class GFG {
public static void main(String[] args)
{
double d = 100.04;
long l = (long)d;
int i = (int)l;
System.out.println("Double value " + d);
System.out.println("Long value " + l);
System.out.println("Int value " + i);
}
}
Output
Double value 100.04 Long value 100 Int value 100
Note: While assigning value to byte type the fractional part is lost and is reduced to modulo 256(range of byte).
Example:
Java
class GFG {
public static void main(String args[])
{
byte b;
int i = 257;
double d = 323.142;
System.out.println("Conversion of int to byte.");
b = (byte)i;
System.out.println("i = " + i + " b = " + b);
System.out.println(
"nConversion of double to byte.");
b = (byte)d;
System.out.println("d = " + d + " b= " + b);
}
}
Output
Conversion of int to byte. i = 257 b = 1 Conversion of double to byte. d = 323.142 b= 67
Type Promotion in Expressions
While evaluating expressions, the intermediate value may exceed the range of operands and hence the expression value will be promoted. Some conditions for type promotion are:
- Java automatically promotes each byte, short, or char operand to int when evaluating an expression.
- If one operand is long, float or double the whole expression is promoted to long, float, or double respectively.
Example:
Java
class GFG {
public static void main(String args[])
{
byte b = 42;
char c = 'a';
short s = 1024;
int i = 50000;
float f = 5.67f;
double d = .1234;
double result = (f * b) + (i / c) - (d * s);
System.out.println("result = " + result);
}
}
Output
result = 626.7784146484375
Explicit Type Casting in Expressions
While evaluating expressions, the result is automatically updated to a larger data type of the operand. But if we store that result in any smaller data type it generates a compile-time error, due to which we need to typecast the result.
Example:
Java
class GFG {
public static void main(String args[])
{
byte b = 50;
b = (byte)(b * 2);
System.out.println(b);
}
}
Note: In case of single operands the result gets converted to int and then it is typecast accordingly, as in the above example.
This article is contributed by Apoorva Singh. If you like GeeksforGeeks and would like to contribute, you can also write an article using write.geeksforgeeks.org or mail your article to review-team@geeksforgeeks.org. See your article appearing on the GeeksforGeeks main page and help other Geeks. Please write comments if you find anything incorrect, or you want to share more information about the topic discussed above.
Java provides various data types just likely any other dynamic languages such as boolean, char, int, unsigned int, signed int, float, double, long, etc in total providing 7 types where every datatype acquires different space while storing in memory. When you assign a value of one data type to another, the two types might not be compatible with each other. If the data types are compatible, then Java will perform the conversion automatically known as Automatic Type Conversion, and if not then they need to be cast or converted explicitly. For example, assigning an int value to a long variable.
| Datatype | Bits Acquired In Memory |
|---|---|
| boolean | 1 |
| byte | 8 (1 byte) |
| char | 16 (2 bytes) |
| short | 16(2 bytes) |
| int | 32 (4 bytes) |
| long | 64 (8 bytes) |
| float | 32 (4 bytes) |
| double | 64 (8 bytes) |
Widening or Automatic Type Conversion
Widening conversion takes place when two data types are automatically converted. This happens when:
- The two data types are compatible.
- When we assign a value of a smaller data type to a bigger data type.
For Example, in java, the numeric data types are compatible with each other but no automatic conversion is supported from numeric type to char or boolean. Also, char and boolean are not compatible with each other.
Example:
Java
class GFG {
public static void main(String[] args)
{
int i = 100;
long l = i;
float f = l;
System.out.println("Int value " + i);
System.out.println("Long value " + l);
System.out.println("Float value " + f);
}
}
Output
Int value 100 Long value 100 Float value 100.0
Narrowing or Explicit Conversion
If we want to assign a value of a larger data type to a smaller data type we perform explicit type casting or narrowing.
- This is useful for incompatible data types where automatic conversion cannot be done.
- Here, the target type specifies the desired type to convert the specified value to.
char and number are not compatible with each other. Let’s see when we try to convert one into another.
Java
public class GFG {
public static void main(String[] argv)
{
char ch = 'c';
int num = 88;
ch = num;
}
}
Output: An error will be generated
This error is generated as an integer variable takes 4 bytes while character datatype requires 2 bytes. We are trying to plot data from 4 bytes into 2 bytes which is not possible.
How to do Explicit Conversion?
Java
public class GFG {
public static void main(String[] args)
{
double d = 100.04;
long l = (long)d;
int i = (int)l;
System.out.println("Double value " + d);
System.out.println("Long value " + l);
System.out.println("Int value " + i);
}
}
Output
Double value 100.04 Long value 100 Int value 100
Note: While assigning value to byte type the fractional part is lost and is reduced to modulo 256(range of byte).
Example:
Java
class GFG {
public static void main(String args[])
{
byte b;
int i = 257;
double d = 323.142;
System.out.println("Conversion of int to byte.");
b = (byte)i;
System.out.println("i = " + i + " b = " + b);
System.out.println(
"nConversion of double to byte.");
b = (byte)d;
System.out.println("d = " + d + " b= " + b);
}
}
Output
Conversion of int to byte. i = 257 b = 1 Conversion of double to byte. d = 323.142 b= 67
Type Promotion in Expressions
While evaluating expressions, the intermediate value may exceed the range of operands and hence the expression value will be promoted. Some conditions for type promotion are:
- Java automatically promotes each byte, short, or char operand to int when evaluating an expression.
- If one operand is long, float or double the whole expression is promoted to long, float, or double respectively.
Example:
Java
class GFG {
public static void main(String args[])
{
byte b = 42;
char c = 'a';
short s = 1024;
int i = 50000;
float f = 5.67f;
double d = .1234;
double result = (f * b) + (i / c) - (d * s);
System.out.println("result = " + result);
}
}
Output
result = 626.7784146484375
Explicit Type Casting in Expressions
While evaluating expressions, the result is automatically updated to a larger data type of the operand. But if we store that result in any smaller data type it generates a compile-time error, due to which we need to typecast the result.
Example:
Java
class GFG {
public static void main(String args[])
{
byte b = 50;
b = (byte)(b * 2);
System.out.println(b);
}
}
Note: In case of single operands the result gets converted to int and then it is typecast accordingly, as in the above example.
This article is contributed by Apoorva Singh. If you like GeeksforGeeks and would like to contribute, you can also write an article using write.geeksforgeeks.org or mail your article to review-team@geeksforgeeks.org. See your article appearing on the GeeksforGeeks main page and help other Geeks. Please write comments if you find anything incorrect, or you want to share more information about the topic discussed above.
Иногда возникают ситуации, когда необходимо переменной одного типа присвоить значение переменной другого типа. Например:
int i = 11;
byte b = 22;
i = b;
В Java существует два типа преобразований — автоматическое преобразование (неявное) и приведение типов (явное преобразование).
Рассмотрим сначала автоматическое преобразование. Если оба типа совместимы, их преобразование будет выполнено в Java автоматически. Например, значение типа byte всегда можно присвоить переменной типа int, как это показано в предыдущем примере.
Для автоматического преобразования типа должно выполняться два условия:
- оба типа должны быть совместимы
- длина целевого типа должна быть больше длины исходного типа
В этом случае происходит преобразование с расширением.
Следующая схема показывает расширяющее преобразование в Java:
Сплошные линии обозначают преобразования, выполняемые без потери данных. Штриховые линии говорят о том, что при преобразовании может произойти потеря точности.
Например, тип данных int всегда достаточно велик, чтобы хранить все допустимые значения типа byte, поэтому никакие операторы явного приведения типов в данном случае не требуются. С точки зрения расширяющего преобразования числовые типы данных, в том числе целочисленные и с плавающей точкой, совместимы друг с другом. В то же время не существует автоматических преобразований числовых типов в тип char или boolean. Типы char и boolean также не совместимы друг с другом.
Стоит немного пояснить почему, к примеру тип byte не преобразуется автоматически (не явно) в тип char, хотя тип byte имеет ширину 8 бит, а char — 16. То же самое касается и преобразования типа short в char. Это происходит потому, что byte и short знаковые типы данных, а char беззнаковый. Поэтому в данном случае требуется использовать явное приведение типов, поскольку компилятору надо явно указать, что вы знаете чего хотите и как будет обрабатываться знаковый бит типов byte и short при преобразовании к типу char.
Поведение величины типа char в большинстве случаев совпадает с поведением величины целого типа, следовательно, значение типа char можно использовать везде, где требуются значения int или long. Однако напомним, что тип char не имеет знака, поэтому он ведет себя отлично от типа short, несмотря на то что диапазон обоих типов равен 16 бит.
Несмотря на все удобство автоматического преобразования типов, оно не в состоянии удовлетворить все насущные потребности. Например, что делать, если значение типа int нужно присвоить переменной типа byte? Это преобразование не будет выполняться автоматически, поскольку длина типа byte меньше, чем у типа int. Иногда этот вид преобразования называется сужающим преобразованием, поскольку значение явно сужается, чтобы уместиться в целевом типе данных.
Чтобы выполнить преобразование двух несовместимых типов данных, нужно воспользоваться приведением типов. Приведение — это всего лишь явное преобразование типов. Общая форма приведения типов имеет следующий вид:
(целевой_тип) значение
где параметр целевой_тип обозначает тип, в который нужно преобразовать указанное значение.
Например, в следующем фрагменте кода тип int приводится к типу byte:
int i = 11;
byte b = 22;
b = (byte) i;
Рассмотрим пример преобразования значений с плавающей точкой в целые числа. В этом примере дробная часть значения с плавающей точкой просто отбрасывается (операция усечения):
double d = 3.89;
int a = (int) d; //Результат будет 3
При приведении более емкого целого типа к менее емкому старшие биты просто отбрасываются:
int i = 323;
byte b = (byte) i; //Результат будет 67
При приведении более емкого значения с плавающей точкой в целое число происходит усечение и отбрасывание старших битов:
double d = 389889877779.89;
short s = (short) d; //Результат будет -1
Помимо операций присваивания, определенное преобразование типов может выполняться и в выражениях.
В языке Java действуют следующие правила:
- Если один операнд имеет тип
double, другой тоже преобразуется к типуdouble. - Иначе, если один операнд имеет тип
float, другой тоже преобразуется к типуfloat. - Иначе, если один операнд имеет тип
long, другой тоже преобразуется к типуlong. - Иначе оба операнда преобразуются к типу
int. - В выражениях совмещенного присваивания (+=,-=,*=,/=) нет необходимости делать приведение.
Приведем пример:
При умножении переменной b1 (byte) на 2 (int) результат будет типа int. Поэтому при попытке присвоить результат в переменную b2 (byte) возникнет ошибка компиляции. Но при использовании совмещенной операции присваивания (*=), такой проблемы не возникнет:
byte b1 = 1;
byte b2 = 2 * b1; //Ошибка компиляции
int i1 = 2 * b1;
b2 *= 2;
В следующем примере тоже возникнет ошибка компиляции — несмотря на то, что складываются числа типа byte, результатом операции будет тип int, а не short.
public class IntegerDemo1 {
public static void main(String[] args) {
byte b1 = 50, b2 = -99;
short k = b1 + b2; //ошибка компиляции
System.out.println("k=" + k);
}
}
Следующий пример аналогичен предыдущему, но используется операция совмещенного присваивание, в которой приведение происходит автоматически:
public class IntegerDemo2 {
public static void main(String[] args) {
byte b1 = 50, b2 = -99;
b1 += b2;
System.out.println("b1=" + b1);
}
}
Презентацию с видео можно скачать на Patreon.
Аннотация: Эта лекция посвящена вопросам преобразования типов. Поскольку Java – язык строго типизированный, компилятор и виртуальная машина всегда следят за работой с типами, гарантируя надежность выполнения программы. Однако во многих случаях то или иное преобразование необходимо осуществить для реализации логики программы. С другой стороны, некоторые безопасные переходы между типами Java позволяет осуществлять неявным для разработчика образом, что может привести к неверному пониманию работы программы.
В лекции рассматриваются все виды преобразований, а затем все ситуации в программе, где они могут применяться. В заключение приводится начало классификации типов переменных и типов значений, которые они могут хранить. Этот вопрос будет подробнее рассматриваться в следующих лекциях.
Введение
Как уже говорилось, Java является строго типизированным языком, а это означает, что каждое выражение и каждая переменная имеет строго определенный тип уже на момент компиляции. Тип устанавливается на основе структуры применяемых выражений и типов литералов, переменных и методов, используемых в этих выражениях.
Например:
long a=3;
a = 5+'A'+a;
print("a="+Math.round(a/2F));
Рассмотрим, как в этом примере компилятор устанавливает тип каждого выражения и какие преобразования (conversion) типов необходимо осуществить при каждом действии.
- В первой строке литерал 3 имеет тип по умолчанию, то есть int. При присвоении этого значения переменной типа long необходимо провести преобразование.
- Во второй строке сначала производится сложение значений типа int и char. Второй аргумент будет преобразован так, чтобы операция проводилась с точностью в 32 бита. Второй оператор сложения опять потребует преобразования, так как наличие переменной a увеличивает точность до 64 бит.
- В третьей строке сначала будет выполнена операция деления, для чего значение long надо будет привести к типу float, так как второй операнд — дробный литерал. Результат будет передан в метод Math.round, который произведет математическое округление и вернет целочисленный результат типа int. Это значение необходимо преобразовать в текст, чтобы осуществить дальнейшую конкатенацию строк. Как будет показано ниже, эта операция проводится в два этапа — сначала простой тип приводится к объектному классу-«обертке» (в данном случае int к Integer ), а затем у полученного объекта вызывается метод toString(), что дает преобразование к строке.
Данный пример показывает, что даже простые строки могут содержать многочисленные преобразования, зачастую незаметные для разработчика. Часто бывают и такие случаи, когда программисту необходимо явно изменить тип некоторого выражения или переменной, например, чтобы воспользоваться подходящим методом или конструктором.
Вспомним уже рассмотренный пример:
int b=1; byte c=(byte)-b; int i=c;
Здесь во второй строке необходимо провести явное преобразование, чтобы присвоить значение типа int переменной типа byte. В третьей же строке обратное приведение производится автоматически, неявным для разработчика образом.
Рассмотрим сначала, какие переходы между различными типами можно осуществить.
Виды приведений
В Java предусмотрено семь видов приведений:
- тождественное (identity);
- расширение примитивного типа (widening primitive);
- сужение примитивного типа (narrowing primitive);
- расширение объектного типа (widening reference);
- сужение объектного типа (narrowing reference);
- преобразование к строке (String);
- запрещенные преобразования (forbidden).
Рассмотрим их по отдельности.
Тождественное преобразование
Самым простым является тождественное преобразование. В Java преобразование выражения любого типа к точно такому же типу всегда допустимо и успешно выполняется.
Зачем нужно тождественное приведение? Есть две причины для того, чтобы выделить такое преобразование в особый вид.
Во-первых, с теоретической точки зрения теперь можно утверждать, что любой тип в Java может участвовать в преобразовании, хотя бы в тождественном. Например, примитивный тип boolean нельзя привести ни к какому другому типу, кроме него самого.
Во-вторых, иногда в Java могут встречаться такие выражения, как длинный последовательный вызов методов:
print(getCity().getStreet().getHouse().getFlat().getRoom());
При исполнении такого выражения сначала вызывается первый метод getCity(). Можно предположить, что возвращаемым значением будет объект класса City. У этого объекта далее будет вызван следующий метод getStreet(). Чтобы узнать, значение какого типа он вернет, необходимо посмотреть описание класса City. У этого значения будет вызван следующий метод ( getHouse() ), и так далее. Чтобы узнать результирующий тип всего выражения, необходимо просмотреть описание каждого метода и класса.
Компилятор без труда справится с такой задачей, однако разработчику будет нелегко проследить всю цепочку. В этом случае можно воспользоваться тождественным преобразованием, выполнив приведение к точно такому же типу. Это ничего не изменит в структуре программы, но значительно облегчит чтение кода:
print((MyFlatImpl)(getCity().getStreet().getHouse().getFlat().getRoom()));
Преобразование примитивных типов (расширение и сужение)
Очевидно, что следующие четыре вида приведений легко представляются в виде таблицы 7.1.
| простой тип, расширение | ссылочный тип, расширение |
| простой тип, сужение | ссылочный тип, сужение |
Что все это означает? Начнем по порядку. Для простых типов расширение означает, что осуществляется переход от менее емкого типа к более емкому. Например, от типа byte (длина 1 байт) к типу int (длина 4 байта). Такие преобразования безопасны в том смысле, что новый тип всегда гарантированно вмещает в себя все данные, которые хранились в старом типе, и таким образом не происходит потери данных. Именно поэтому компилятор осуществляет его сам, незаметно для разработчика:
В последней строке значение переменной b типа byte будет преобразовано к типу переменной a (то есть, int ) автоматически, никаких специальных действий для этого предпринимать не нужно.
Следующие 19 преобразований являются расширяющими:
- от byte к short, int, long, float, double
- от short к int, long, float, double
- от char к int, long, float, double
- от int к long, float, double
- от long к float, double
- от float к double
Обратите внимание, что нельзя провести преобразование к типу char от типов меньшей или равной длины ( byte, short ), или, наоборот, к short от char без потери данных. Это связано с тем, что char, в отличие от остальных целочисленных типов, является беззнаковым.
Тем не менее, следует помнить, что даже при расширении данные все-таки могут быть в особых случаях искажены. Они уже рассматривались в предыдущей лекции, это приведение значений int к типу float и приведение значений типа long к типу float или double. Хотя эти дробные типы вмещают гораздо большие числа, чем соответствующие целые, но у них меньше значащих разрядов.
Повторим этот пример:
long a=111111111111L; float f = a; a = (long) f; print(a);
Результатом будет:
Обратное преобразование — сужение — означает, что переход осуществляется от более емкого типа к менее емкому. При таком преобразовании есть риск потерять данные. Например, если число типа int было больше 127, то при приведении его к byte значения битов старше восьмого будут потеряны. В Java такое преобразование должно совершаться явным образом, т.е. программист в коде должен явно указать, что он намеревается осуществить такое преобразование и готов потерять данные.
Следующие преобразования являются сужающими:
- от byte к char
- от short к byte, char
- от char к byte, short
- от int к byte, short, char
- от long к byte, short, char, int
- от float к byte, short, char, int, long
- от double к byte, short, char, int, long, float
При сужении целочисленного типа к более узкому целочисленному все старшие биты, не попадающие в новый тип, просто отбрасываются. Не производится никакого округления или других действий для получения более корректного результата:
print((byte)383); print((byte)384); print((byte)-384);
Результатом будет:
Видно, что знаковый бит при сужении не оказал никакого влияния, так как был просто отброшен — результат приведения противоположных чисел (384 и -384) оказался одинаковым. Следовательно, может быть потеряно не только точное абсолютное значение, но и знак величины.
Это верно и для типа char:
char c=40000; print((short)c);
Результатом будет:
Сужение дробного типа до целочисленного является более сложной процедурой. Она проводится в два этапа.
На первом шаге дробное значение преобразуется в long, если целевым типом является long, или в int — в противном случае (целевой тип byte, short, char или int ). Для этого исходное дробное число сначала математически округляется в сторону нуля, то есть дробная часть просто отбрасывается.
Например, число 3,84 будет округлено до 3, а -3,84 превратится в -3. При этом могут возникнуть особые случаи:
- если исходное дробное значение является NaN, то результатом первого шага будет 0 выбранного типа (т.е. int или long );
- если исходное дробное значение является положительной или отрицательной бесконечностью, то результатом первого шага будет, соответственно, максимально или минимально возможное значение для выбранного типа (т.е. для int или long );
- наконец, если дробное значение было конечной величиной, но в результате округления получилось слишком большое по модулю число для выбранного типа (т.е. для int или long ), то, как и в предыдущем пункте, результатом первого шага будет, соответственно, максимально или минимально возможное значение этого типа. Если же результат округления укладывается в диапазон значений выбранного типа, то он и будет результатом первого шага.
На втором шаге производится дальнейшее сужение от выбранного целочисленного типа к целевому, если таковое требуется, то есть может иметь место дополнительное преобразование от int к byte, short или char.
Проиллюстрируем описанный алгоритм преобразованием от бесконечности ко всем целочисленным типам:
float fmin = Float.NEGATIVE_INFINITY;
float fmax = Float.POSITIVE_INFINITY;
print("long: " + (long)fmin + ".." +
(long)fmax);
print("int: " + (int)fmin + ".." +
(int)fmax);
print("short: " + (short)fmin + ".." +
(short)fmax);
print("char: " + (int)(char)fmin + ".." +
(int)(char)fmax);
print("byte: " + (byte)fmin + ".." +
(byte)fmax);
Результатом будет:
long: -9223372036854775808..9223372036854775807 int: -2147483648..2147483647 short: 0..-1 char: 0..65535 byte: 0..-1
Значения long и int вполне очевидны — дробные бесконечности преобразовались в, соответственно, минимально и максимально возможные значения этих типов. Результат для следующих трех типов ( short, char, byte ) есть, по сути, дальнейшее сужение значений, полученных для int, согласно второму шагу процедуры преобразования. А делается это, как было описано, просто за счет отбрасывания старших битов. Вспомним, что минимально возможное значение в битовом виде представляется как 1000..000 (всего 32 бита для int, то есть единица и 31 ноль). Максимально возможное — 1111..111 (31 единица). Отбрасывая старшие биты, получаем для отрицательной бесконечности результат 0, одинаковый для всех трех типов. Для положительной же бесконечности получаем результат, все биты которого равняются 1. Для знаковых типов byte и short такая комбинация рассматривается как -1, а для беззнакового char — как максимально возможное значение, то есть 65535.
Может сложиться впечатление, что для char приведение дает точное значение. Однако это был частный случай — отбрасывание битов в большинстве случаев все же дает искажение. Например, сужение дробного значения 2 миллиарда:
float f=2e9f; print((int)(char)f); print((int)(char)-f);
Результатом будет:
Обратите внимание на двойное приведение для значений типа char в двух последних примерах. Понятно, что преобразование от char к int не приводит к потере точности, но позволяет распечатывать не символ, а его числовой код, что более удобно для анализа.
В заключение еще раз обратим внимание на то, что примитивные значения типа boolean могут участвовать только в тождественных преобразованиях.
В Java существует много типов данных. В большинстве случаев при кодировании необходимо изменить тип данных, чтобы понять обработку переменной, и это называется приведением типа.
Приведение типов в Java – это присвоение значения одного примитивного типа данных другому. Вы должны знать о совместимости этого типа данных. Если они совместимы, тогда Java выполнит преобразование, известное как автоматическое преобразование типов, а если нет, то их необходимо явно преобразовать.
В Java есть два типа приведения:
- Расширение приведения (автоматически) – преобразование меньшего типа данных в больший размер типа.
byte -> short -> char -> int -> long -> float -> double - Сужение приведения (вручную) – преобразование данных большего размера в тип меньшего размера.
double -> float -> long -> int -> char -> short -> byte
Неявное
Тип приведения, когда два типа данных автоматически конвертируются. Также известно как неявное преобразование. Происходит, когда два типа данных совместимы, а также когда мы присваиваем значение меньшего типа данных большему типу данных.
Например, числовые типы данных совместимы друг с другом, но автоматическое преобразование из числового типа в тип char или boolean не поддерживается.
Кроме того, char и boolean не совместимы друг с другом. Теперь давайте напишем логику для неявного приведения типов, чтобы понять, как это работает.
public class Conversion{
public static void main(String[] args)
{
int i = 200;
//automatic type conversion
long l = i;
//automatic type conversion
float f = l;
System.out.println("Int value "+i);
System.out.println("Long value "+l);
System.out.println("Float value "+f);
}
}
Вывод:
Int value 200 Long value 200 Float value 200.0
Явное
В этом случае, если вы хотите присвоить значение большего типа данных меньшему типу данных, вы можете выполнить явное приведение или сужение типов. Это полезно для несовместимых типов данных, где автоматическое преобразование невозможно.
Давайте разберемся с этим на примере.
//Java program to illustrate explicit type conversion
public class Narrowing
{
public static void main(String[] args)
{
double d = 200.06;
//explicit type casting
long l = (long)d;
//explicit type casting
int i = (int)l;
System.out.println("Double Data type value "+d);
//fractional part lost
System.out.println("Long Data type value "+l);
//fractional part lost
System.out.println("Int Data type value "+i);
}
}
Вывод:
Double Data type value 200.06 Long Data type value 200 Int Data type value 200
Явное приведение в выражениях
Когда вы вычисляете выражения, выходные данные автоматически обновляются до большего типа данных операнда. Но если вы сохраните этот результат в каком-либо меньшем типе данных, он генерирует ошибку времени компиляции, из-за которой нам нужно набрать приведение вывода.
Пример:
//Java program to illustrate type casting int to byte
public class ExplicitTest {
public static void main(String args[])
{
byte b = 70;
//type casting int to byte
b = (byte)(b * 2);
System.out.println(b);
}
}
Вывод:
140
Примечание: в случае одиночных операндов результат конвертируется в int, а затем соответственно преобразуется в тип.
Афоризм
Лучше с любовью заниматься трудом, чем с трудом заниматься любовью.
Михаил Жванецкий
Поддержка проекта
Если Вам сайт понравился и помог, то будем признательны за Ваш «посильный» вклад в его поддержку и развитие
• Yandex.Деньги
410013796724260
• Webmoney
R335386147728
Z369087728698
Типы данных, приведение, операции
В Java используется несколько типов данных (java types) :
- Целочисленные
- Вещественные
- Логические
- Строковые
- Примитивные
Целочисленные данные — byte, short, int, long
| Тип данных | Объём памяти | Диапазон значений |
|---|---|---|
| byte | 1 байт | -128…127 (-27… 27) |
| short | 2 байта | -32 768…32 767 (-215… 215) |
| int | 4 байта | -2 147 483 648 .. 2 147 483 647 (-231… 231) |
| long | 8 байт | -9 223 372 036 854 775 808 .. 9 223 372 036 854 775 807 (-263… 263) |
Пример применения целочисленных данных java — byte, short, int, long
public class Type
{
public static void main (String [] arg)
{
int i = 4 + 5;
byte b = -128 + 127;
short s = 22223 + 1;
long l = 334+11232143;
System.out.println (i);
System.out.println (b);
System.out.println (s);
System.out.println (l);
}
}
Вещественные типы данных — float, double
| Тип данных | Объём памяти | Диапазон значений |
|---|---|---|
| float | 4 байта | ~1,4*10-45…~3,4*1038 |
| double | 8 байт | ~4,9*10-324… ~1,8*10308 |
Пример применения вещественных типов данных java — float, double
public class DoubleFloat
{
public static void main (String [] arg)
{
double b1 = 3.62;
double b2 = 4.12 + b1;
float pi = 3.14f;
// При использовании типа float необходимо
// использовать приведение типа, так как дробные
// числа - это литералы типа double
float pipi = (float) 3.14;
double d = 27;
double c = pi * d;
System.out.println (c);
}
}
Логический тип данных
Под логические значения в Java отводится тип boolean, которое может принимать только одно из двух
возможных значений true (истина) и false (ложь).
Символьный тип данных — char
Для хранения символов в Java используется тип char размером 2 байта (16 бит). Диапазон
значений варьируется от 0 до 65536.
Литералы java
2 // литерал типа int
010 // литерал типа int заданный в восьмеричной системе
// счисления, признаком использования восьмеричной
// системы является нуль в начале числа, в
// десятеричной системе это будет число 8
0x10 // литерал типа int заданный в шестнадцатеричной
// системе счисления, признаком её использования
// является 0x в начале числа, в десятеричной
1.2 // системе это будет число 16 литерал типа double
2e5 // литерал типа double, записанный в научной
// нотации, число после e надо воспринимать
// как показатель степени десятки, на которую
// умножается число указанное до e, т.е. в данном
// случае записано число 2*10^5 = 200000
-1.23e-3 // литерал типа double, -1.23*10^-3 = -0.00123
2L // литерал типа long, можно использовать
// строчную букву l
2F // литерал типа float, можно использовать
// строчную букву f
2D // литерал типа double, можно использовать
// строчную букву d
2e-2f // литерал типа float, численно равен 0.02
false // литерал типа boolean
'a' // литерал типа char — печатный символ,
// задаётся в одинарных кавычках
't' // литерал типа char — специальный символ, не
// отображается в виде какого-либо значка на
// экране, но управляет выводом или его
// форматированием, например, данный символ
// добавляет в вывод символ табуляции (отступа)
'u004D'; // литерал типа char заданный своим кодом в
// шестнадцатеричной системе счисления по
// кодовой таблице Unicode, данный код
// соответствует букве «M»
"Россия" // литерал класса String — строка символов,
// задаётся в двойных кавычках, может содержать
// любые литералы типа char, в том числе состоять
// из единственного символа или быть пустой
"Приnвет" // литерал класса String включающий спецсимвол n,
// обрывающий строку, при выводе на экран слоги
// «При» и «вет» разместятся на разных строках
// друг под другом
Переменная класса java
Переменная — это именованная область памяти, куда может быть (пере)записано и откуда может быть прочитано значение
определенного типа. Тип переменной и её имя задаются при создании переменной, они не могут быть изменены далее по ходу
программы.
Имя или идентификатор переменной — это последовательность из строчных и заглавных латинских букв, цифр, а также
символов «$» и «_». Имя переменной может начинаться с любого из перечисленных символов, кроме цифры.
При создании (объявлении) переменных нужно указывать имя и тип каждой из них.
int aM; // создали переменную aM типа int
double ch_PI; // создали переменную ch_PI типа double
int c, d; // несколько переменных одного типа можно
// объявить в одной строке, перечислив их
// через запятую, в данном случае созданы
// переменные c и d типа int
Язык Java чувствителен к регистру символов в идентификаторах, т.е. идентификаторы Chis, CHIS и cHiS — в Java
различны. Внутри одного блока не может существовать несколько элементов с одинаковыми идентификаторами.
Операция java
Операция — это некое элементарное действие (например, сложение чисел), обозначаемое в языке Java заранее
предопределенной последовательностью символов, которое может выполняться над одной или несколькими переменными и
литералами.
Фрагмент кода, где в одну конструкцию объединяется несколько операций — называется выражением.
Операция присваивания
Операция присваивания обозначается символом «=». Она вычисляет значение своего правого операнда и присваивает
его левому операнду.
int a; a = 5; // переменной a присвоили значение 5
В простейшем случае, литерал используется в выражении с оператором присваивания для задания начального значения
акой-либо переменной.
Объявление переменной и определение её начального значения — инициализация переменных — можно совместить :
float k1 = 13.3; boolean b1 = true, b2 = true, b3 = false; // и даже для нескольких переменных одного типа
Присваивать значение литералу — нельзя :
5 = a; // это ошибка, литералу нельзя присвоить значение
Если переменная располагается справа от оператора присваивания или используется как аргумент какого-то метода,
то происходит чтение её значения (т. е. мысленно можно заменить переменную литералом, который в неё хранится на
текущем шаге программы).
// переменной w будет присвоено значение a int w = a; // В консоле будет отображено значение w System.out.println(w);
Любой переменной до того, как она впервые будет использована для чтения — нужно присвоить какое-то значение, иначе,
произойдёт ошибка компиляции. Значения можно не присваивать полям классов (им будут присваиваться значения по умолчанию,
отражённые в таблице базовых типов).
Также операция присваивания возвращает в качестве результата присвоенное значение. Это значение может быть использовано
другими операциями (в том числе, другим присваиванием). Последовательность из нескольких операций присваивания выполняется
справа налево.
int v, a, w = 5;
System.out.println(a=6); // переменной a будет присвоено
// значение 6 и в консоле
// отображено 6
v = a = -3; // переменным a и v будет
// присвоено значение -3
System.out.println(v=a=w); // переменным a и v будет присвоено
// значение, взятое из w, оно же
// будет выведено в консоль
Преобразование типов
При всём многообразии типов часто возникают ситуации, когда данные одного типа нужно преобразовать к другому типу.
Некоторые преобразования происходят неявно. Рассмотрим такой пример:
double a = 3; System.out.println(a); // в консоле будет отображено 3.0
Переменная типа double предусматривает хранение не только целой, но и десятичной части числа, т.е. фактически
в переменную запишется значение 3.0 (три целых и ноль десятых), которое потом и выведется на экран с помощью следующей команды.
Java преобразовала целочисленное значение 3 в вещественное 3.0 самостоятельно, без явного участия разработчика. Такое
преобразование (называемое также «приведение«) типа данных называется неявным или автоматическим.
Оно происходит всякий раз, когда в процессе преобразования не могут потеряться какие-либо данные (т.е. когда преобразования
производится к более универсальному типу: от коротких целых short к длинным целым long, от целых int к
вещественным double и т.п.).
Потеря точности может происходить, когда будет предпринята попытка из вещественного числа получить целое. Это можно сделать
округлив число или взяв только его целую часть. Но дробную часть при этом придётся забыть, и, если она не была нулевой, то
какие-то полезные данные могут потеряться.
Например, если мы произведём следующее присваивание, то при попытке откомпилировать программу получим ошибку
«возможна потеря точности»:
int a = 3.14; // ошибка possible loss of precision
Но даже если десятичная часть была бы нулевой (справа стояло бы значение 3.0), то мы получили бы ту же ошибку. То есть
Java не занимается анализом самого значения, а обращает внимание только на его тип.
Явное преобразование
Тем не менее, преобразовать вещественное значение к целому можно, явно сообщив в программе о своём намерении.
Для этого слева от исходного элемента надо в круглых скобках указать название типа, к которому его нужно привести.
int a = (int) 3.14; // приведение типа System.out.println(a); // выведет в консоль 3
Такое преобразование с указанием целевого типа называется явным. Явное преобразование вещественного значения
к целому типу происходит за счёт отбрасывания десятичной части (берётся только целая часть).
double b = 2.6;
int c = (int) (0.5 + b); // можно применять
// к целым выражениям
System.out.println(c); // выведет 3
System.out.println((int)9.69); // выведет 9
System.out.println((int)'A') ; // выведет 65 — код символа «A»
System.out.println((double)3); // выведет 3.0
Явное преобразование может потребоваться также в тех случаях, когда значение типа позволяющего хранить
большее количество знаков надо привести к типу, способному хранить меньшее количество знаков числа. Например, когда
long надо преобразовать к short. О том, как происходят такие преобразования, будет рассказано далее при обсуждении
принципов хранения данных в памяти компьютера.
Арифметические операции
Арифметические операции — это бинарные операции, в которых участвует два операнда числового типа.
+ складывает оба операнда и возвращает результат сложения.
— вычитает из первого операнда второй.
* перемножает операнды и возвращает результат.
/ делит первый операнд на второй без остатка (выполняет деление нацело), если оба операнда целые, и выполняет деление
с остатком, в случае, если хотя бы один из операндов вещественный.
% возвращает остаток от деления первого операнда на второй (иначе говоря, приводит первый аргумент по модулю второго).
Напомним, что наименьший остаток при делении на любое натуральное n равняется нулю, а наибольший равняется n-1.
Если в какой-то арифметической операции задействованы аргументы разных типов, то перед выполнением операции все
аргументы автоматически приводятся к более универсальному из задействованных типов.
System.out.println(2+3); // выведет 5
System.out.println(10%3); // выведет 1 (остаток от
// деления на целое число)
System.out.println(12%3); // выведет 0
System.out.println(9/2); // выведет 4
System.out.println(9/2.0); // выведет 4.5
System.out.println(9d/2); // выведет 4.5
System.out.println((double)7/2); // выведет 3.5
System.out.println((double)(7/2)); // выведет 3.0, ведь к
// целым преобразуется уже
// результат деления нацело
Приоритет операций
В одном выражении может использоваться сразу несколько операций. Приоритет их будет таким:
- Умножение, деление, вычисление остатка.
- Сложение и вычитание.
- Присваивание.
Операции с одинаковым приоритетом (перечисленные в одном пункте представленного списка, например, сложение и
вычитание) выполняются в порядке следования в выражении, слева направо. Приоритет можно скорректировать с помощью
круглых скобок (операции в круглых скобках выполняются в первую очередь). Круглые скобки допускают многократное
вложение.
System.out.println(7%3*4); // выводится 4 System.out.println(4*7%3); // выводится 1 System.out.println(4*(7%3)); // выводится 4
Хочется напомнить, что переменные типа char — хранят числовые значения (коды символов по кодовой таблице),
а поэтому также могу участвовать в арифметических операциях. Рассмотрите следующий пример, учитывая, что десятичный
код символа ‘Q’ равен 81:
int t; t = 162/'Q'; System.out.println(t); // выводится 2
Наверх

















