Память в Java с точки зрения программиста представляется не нулями и единицами или набором байтов, а как некое виртуальное пространство, в котором существуют объекты. И доступ к памяти осуществляется не по физическому адресу или указателю, а лишь через ссылки на объекты. Ссылка возвращается при создании объекта и далее может быть сохранена в переменной, передана в качестве аргумента и т.д. Как уже говорилось, допускается наличие нескольких ссылок на один объект. Возможна и противоположная ситуация – когда на какой-то объект не существует ни одной ссылки. Такой объект уже недоступен программе и является "мусором", то есть без толку занимает аппаратные ресурсы. Для их освобождения не требуется никаких усилий. В состав любой виртуальной машины обязательно входит автоматический сборщик мусора garbage collector – фоновый процесс, который как раз и занимается уничтожением ненужных объектов.
Очень важно помнить, что объектная переменная, в отличие от примитивной, может иметь значение другого типа, не совпадающего с типом переменной. Например, если тип переменной – некий класс, то переменная может ссылаться на объект, порожденный от наследника этого класса. Все случаи подобного несовпадения будут рассмотрены в следующих разделах курса.
Теперь рассмотрим примитивные и ссылочные типы данных более подробно.
Примитивные типы
Как уже говорилось, существует 8 простых типов данных, которые делятся на целочисленные ( integer ), дробные ( floating-point ) и булевы ( boolean ).
Целочисленные типы
Целочисленные типы – это byte, short, int, long, также к ним относят и char . Первые четыре типа имеют длину 1, 2, 4 и 8 байт соответственно, длина char – 2 байта, это непосредственно следует из того, что все символы Java описываются стандартом Unicode. Длины типов приведены только для оценки областей значения. Как уже говорилось, память в Java представляется виртуальной и вычислить, сколько физических ресурсов займет та или иная переменная, так прямолинейно не получится.
4 основных типа являются знаковыми. char добавлен к целочисленным типам данных, так как с точки зрения JVM символ и его код – понятия взаимооднозначные. Конечно, код символа всегда положительный, поэтому char – единственный беззнаковый тип. Инициализировать его можно как символьным, так и целочисленным литералом. Во всем остальном char – полноценный числовой тип данных, который может участвовать, например, в арифметических действиях, операциях сравнения и т.п. В таблице 4.1 сведены данные по всем разобранным типам:
Таблица 4.1. Целочисленные типы данных.Название типаДлина (байты)Область значенийbyte1-128 .. 127short2-32.768 .. 32.767int4-2.147.483.648 .. 2.147.483.647long8-9.223.372.036.854.775.808 .. 9.223.372.036.854.775.807 (примерно 1019)char2'\u0000' .. '\uffff', или 0 .. 65.535
Обратите внимание, что int вмещает примерно 2 миллиарда, а потому подходит во многих случаях, когда не требуются сверхбольшие числа. Чтобы представить себе размеры типа long, укажем, что именно он используется в Java для отсчета времени. Как и во многих языках, время отсчитывается от 1 января 1970 года в миллисекундах. Так вот, вместимость long позволяет отсчитывать время на протяжении миллионов веков(!), причем как в будущее, так и в прошлое.
Почему были выделены именно эти два типа, int и long? Дело в том, что целочисленные литералы имеют тип int по умолчанию, или тип long, если стоит буква L или l. Именно поэтому корректным литералом считается только такое число, которое укладывается в 4 или 8 байт, соответственно. Иначе компилятор сочтет это ошибкой. Таким образом, следующие литералы являются корректными:
1 -2147483648 2147483648L 0L 111111111111111111L
Над целочисленными аргументами можно производить следующие операции:
операции сравнения (возвращают булево значение)
<, <=, >, >=
==, !=
числовые операции (возвращают числовое значение)
унарные операции + и -
арифметические операции +, -,
операции инкремента и декремента (в префиксной и постфиксной форме): ++ и --
операции битового сдвига <<, >>, >>>
битовые операции ~, &, |, ^
оператор с условием ?:
оператор приведения типов
оператор конкатенации со строкой +
Операторы сравнения вполне очевидны и отдельно мы их рассматривать не будем. Их результат всегда булева типа ( true или false ).
Работа числовых операторов также понятна, к тому же пояснялась в предыдущей лекции. Единственное уточнение можно сделать относительно операторов + и -, которые могут быть как бинарными (иметь два операнда), так и унарными (иметь один операнд). Бинарные операнды являются операторами сложения и вычитания, соответственно. Унарный оператор + возвращает значение, равное аргументу ( +x всегда равно x ). Унарный оператор -, примененный к значению x, возвращает результат, равный 0-x. Неожиданный эффект имеет место в том случае, если аргумент равен наименьшему возможному значению примитивного типа.