Базовые типы Java, литералы, переменные и константы, приведение типов, основные операторы

В Java существуют следующие базовые типы данных:

Тип данных Объём занимаемой памяти Диапазон допустимых значений Значение по умолчанию (для полей класса)
byte 1 байт Целые из [-128;127] что эквивалентно [-27;27] 0
short 2 байта Целые из [-32768; 32767] или [-215;215] 0
int 4 байта Целые из [-2147483648; 2147483647] или [-231;231] 0
long 8 байт Целые из [-263;263] 0L
float 4 байта Вещественные положительные и отрицательные числа от ~1,4*10-45 до ~3,4*1038 по стандарту IEEE 754 0.0f
double 8 байт Вещественные положительные и отрицательные числа от ~4,9*10-324 до ~1,8*10308 по стандарту IEEE 754 0.0d
char 2 байта Натуральные из [0;65535], интерпретируются как коды символов по таблице Unicode '\u0000'
boolean Для хранения значения этого типа достаточно 1 бита, но в реальности память такими порциями не выделяется, поэтому переменные этого типа могут быть по-разному упакованы виртуальной машиной false либо true false

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

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

Литералы

Литералы — это явно заданные значения одного из допустимых типов, которые могут использоваться в различных выражениях языка (например, как аргумент метода, выводящего что-либо на экран).

Примеры литералов:

2 // литерал типа int

010 // литерал типа int заданный в восьмеричной системе счисления, признаком использования восьмеричной системы является нуль в начале числа, в десятеричной системе это будет число 8

0x10 // литерал типа int заданный в шестнадцатеричной системе счисления, признаком её использования является 0x в начале числа, в десятеричной системе это будет число 16

1.2 // литерал типа 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, обрывающий строку, при выводе на экран слоги «При» и «вет» разместятся на разных строках друг под другом

Переменные

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

Имя или идентификатор переменной — это последовательность из строчных и заглавных латинских букв, цифр, а также символов «$» и «_». Имя переменной может начинаться с любого из перечисленных символов, кроме цифры.

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

int aM; // создали переменную aM типа int

double ch_PI; // создали переменную ch_PI типа double

int c, d; // несколько переменных одного типа можно объявить в одной строке, перечислив их через запятую, в данном случае созданы переменные c и d типа int

Язык Java чувствителен к регистру символов в идентификаторах, т.е. идентификаторы Chis, CHIS и cHiS — в Java различны.

Внутри одного блока не может существовать несколько элементов с одинаковыми идентификаторами.

Операции

Операция — это некое элементарное действие (например, сложение чисел), обозначаемое в языке Java заранее предопределенной последовательностью символов, которое может выполняться над одной или несколькими переменными и литералами.

Фрагмент кода, где в одну конструкцию объединяется несколько операций — называется выражением.

Операция присваивания

Операция присваивания обозначается символом «=». Она вычисляет значение своего правого операнда и присваивает его левому операнду.

int a;
a = 5; // в переменную a присвоили значение 5

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

Объявление переменной и задание её начального значения (этот процесс также называется — инициализацией переменной) можно совместить:

float k1 = 13.3;
boolean b1 = true, b2 = true b3 = false; // и даже для нескольких переменных одного типа

Присваивать значение литералу — нельзя:

5 = a; // это ошибка, в литерал нельзя присвоить значение

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

int w = a; // из переменной a будет прочитано значение 5 и записано в w
System.out.println(w); // из переменной w будет прочитано 5 и выведено на экран

Любой переменной до того, как она впервые будет использована для чтения — нужно присвоить какое-то значение. Иначе, произойдёт ошибка компиляции. Значения можно не присваивать полям классов (им будут присваиваться значения по умолчанию, отражённые в таблице базовых типов), мы вспомним об этом, когда перейдём к созданию собственных классов, но пока весь наш программный код располагается внутри метода main — следует инициализировать переменные.

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

System.out.println(a=6); // в переменную a будет записано 6 и на экран выведется 6

int v;

v = a = -3; // в переменную a будет записано -3, а затем это же значение будет передано следующему оператору присваивания и записано в v тоже запишется -3

System.out.println(v=a=w); // во всех трёх переменных окажется значение 5, взятое из 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, ведь к целым преобразуется уже результат деления нацело

Приоритет операций

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

Приоритет их будет таким:

  1. Умножение, деление, вычисление остатка.

  2. Сложение и вычитание.

  3. Присваивание.

Операции с одинаковым приоритетом (перечисленные в одном пункте представленного списка, например, сложение и вычитание) выполняются в порядке следования в выражении, слева направо.

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

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

Задачи

  1. В переменных q и w хранятся два натуральных числа. Создайте программу, выводящую на экран результат деления q на w с остатком. Пример вывода программы (для случая, когда в q хранится 21, а в w хранится 8):

    21 / 8 = 2 и 5 в остатке

  2. В переменной n хранится натуральное двузначное число. Создайте программу, вычисляющую и выводящую на экран сумму цифр числа n.

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

  4. В переменной n хранится натуральное трёхзначное число. Создайте программу, вычисляющую и выводящую на экран сумму цифр числа n.