Понимание типов данных в Java
Автор выбрал программу Write for DOnations.
Введение
PHP. В динамически типизированных языках вам не нужно указывать тип данных переменной, что может показаться облегчением.
Однако знание типов данных и их правильное использование позволяет разработчикам оптимизировать свой код, поскольку каждый тип данных требует определенных ресурсов. Кроме того, если вы укажете один тип данных и попытаетесь сохранить другой тип, например, по ошибке, вы не сможете скомпилировать код. Таким образом, со статически типизированными языками вы можете обнаружить ошибки еще до любого тестирования.
Java имеет две переменные для хранения и использования информации в программе Java, чтобы узнать о некоторых наиболее часто используемых типах данных в Java. Это не исчерпывающий обзор всех типов данных, но это руководство поможет вам ознакомиться с тем, какие параметры доступны вам в Java.
Предпосылки
Чтобы следовать этому руководству, вам понадобятся:
- Среда, в которой вы можете выполнять программы Java, чтобы следовать примерам. Чтобы настроить это на вашем локальном компьютере, вам потребуется следующее:
- На вашем компьютере установлена Java (версия 11 или выше) с компилятором, входящим в комплект Java Development Kit (JDK). Для Ubuntu и Debian следуйте инструкциям по загрузке для установки Java.
- Для компиляции и запуска примеров кода в этом руководстве используется руководство Introduction to JShell.
Знакомство с Java и объектно-ориентированным программированием, которое вы можете найти в нашем руководстве «Как написать свою первую программу на Java».
Примитивные типы
Примитивные типы в Java — это самые простые и основные типы данных в Java. Они представляют необработанные значения, такие как числа и символы. Наиболее часто используемые примитивные типы данных:
int
(целые числа),boolean
(логические значения) иchar
(символы). Остальное можно найти в официальной документации по типам данных Java.Целые числа
Целые числа являются как отрицательными, так и положительными целыми числами. В Java вы будете использовать
int
для их хранения.int
может вместить достаточно большие числа для большинства целей: от-2 147 483 648
до2 147 483 647
.Давайте посмотрим, как
int
используется в примере:int theAnswer = 42;
Примитивные типы всегда начинаются со строчной буквы (
int
). Правила синтаксиса Java требуют, чтобы вы сначала указали тип данных (int
), а затем его имя (theAnswer
). После этого вы присваиваете переменной значение42
со знаком равенства (=
).Независимо от типа данных, вы используете переменную, напрямую указывая ее имя без добавления каких-либо специальных символов. Это потому, что Java может распознать его как переменную.
Примечание. Имя переменной
theAnswer
и все остальные переменные в этом руководстве написаны в верблюжьем регистре. Несмотря на то, что нет строгих требований к его использованию, это общепринятое соглашение об именах в Java.Как только вы объявили переменную, вы можете использовать ее, ссылаясь на нее в методе, подобном этому:
int theAnswer = 42; System.out.println("The answer to all questions is " + theAnswer);
Во второй строке вы печатаете
theAnswer
в консоль, используя встроенный методprintln
из пакетаSystem.out
. Это самый простой способ проверить переменную, чтобы убедиться, что она объявлена должным образом.Чтобы увидеть этот код в действии, используйте инструмент Java Shell. После установки Java откройте терминал или командную строку на локальном компьютере и введите
jshell
:- jshell
Ваш вывод будет выглядеть примерно так:
Output| Welcome to JShell -- Version 11.0.16 | For an introduction type: /help intro jshell>Вы можете вставить примеры кода из этого руководства в консоль. Когда вы закончите, вы можете выйти из
jshell
, набрав/exit
.Чтобы объявить и использовать
int
, вставьте следующие строки в консольjshell
:- int theAnswer = 42;
- System.out.println("The answer to all questions is " + theAnswer);
Вы увидите следующий вывод:
OutputtheAnswer ==> 42 The answer to all questions is 42Эти выходные данные подтверждают, что вы правильно установили для переменной
int
theAnswer
значение 42 (theAnswer ==> 42
). Вы также успешно использовалиtheAnswer
, передав его методу, и метод выдал ожидаемое значение переменной.логический
Логические значения —
true
илиfalse
. В Java вы будете использоватьboolean
для их хранения. Например, давайте создадим переменнуюboolean
, определяющую, нравится ли Java:boolean isJavaFun = true;
Вы определяете переменную
isJavaFun
какtrue
. Альтернативным значениемboolean
являетсяfalse
.Используя приведенную выше переменную, вы можете вывести предложение
Java is fun: true
следующим образом:- boolean isJavaFun = true;
- System.out.println("Java is fun: " + isJavaFun);
Выполнение этих строк в
jshell
приведет к следующему выводу:OutputisJavaFun ==> true Java is fun: trueПодобно примеру
int
, методprintln
будет печатать аргумент, указанный в скобках. Знак «плюс» (+
) объединяет или объединяет строку «Java is fun:» с переменнойisJavaFun
, так что на самом деле это всего лишь один аргумент — строкаJava — это весело: правда
.Персонажи
Чтобы сохранить один буквенно-цифровой символ, вы будете использовать
char
. Например:char firstLetter = 'a';
Обратите внимание, что буква
a
заключена в одинарные кавычки. Одинарные кавычки можно использовать только для значенийchar
. Двойные кавычки используются для строк, как вы узнаете позже.char
не кажется особенно полезным типом, потому что маловероятно, что вам понадобится переменная, назначенная одному символу. Однакоchar
используется в качестве строительного блока для классов символьных строк, таких какString
, которые в основном представляют собой набор значенийchar
.Как вы видели в этом разделе, объявление и использование переменных примитивного типа очень просто, поскольку они представляют простые значения, такие как целые числа. Эти значения готовы к использованию и не требуют дополнительных операций, таких как создание объектов, вызов методов и т.д.
Ссылочные типы
В первом учебнике этой серии «Как написать свою первую программу на Java» вы узнали, что код Java организован в классы и что эти классы используются в качестве шаблонов для создания объектов. Когда такие объекты назначаются переменным, вы указываете или ссылаетесь на эти объекты. В этих случаях переменные классифицируются как ссылочные типы. Эти переменные также называются непримитивными, поскольку переменные примитивного типа не могут указывать на объекты.
Объекты являются мощными, потому что они имеют расширенные свойства и могут действовать, когда вы активируете их методы. Однако без переменных, указывающих на них, эти объекты недоступны и практически непригодны для использования. Вот почему переменные ссылочного типа необходимы для Java и объектно-ориентированного программирования в целом.
Примечание. Ссылочные типы указывают на объекты, созданные из классов. Во избежание путаницы в следующих примерах ссылочный тип и создаваемый объект будут одного класса.
Однако в сложных программах это бывает редко. В Java интерфейс — это группа требований для определенного поведения, и эти требования могут быть удовлетворены одним или несколькими классами. Говорят, что класс, удовлетворяющий требованиям интерфейса, реализует этот интерфейс. Таким образом, в сложных программах принято объявлять переменную со ссылочным типом интерфейса. Таким образом, вы указываете поведение, которое должна демонстрировать ваша переменная, не привязывая ее к конкретной реализации этого поведения. Это позволяет вам легко изменить реализацию, на которую указывает ваша переменная, без необходимости менять способ использования переменной. Эта сложная концепция является частью более сложной темы о наследовании и полиморфизме, которая будет отдельным учебником в нашей серии статей по Java.
В то время как существует всего несколько примитивных типов, ссылочные типы практически не ограничены, потому что нет ограничений на количество классов (и интерфейсов), и каждый класс обозначает ссылочный тип. В Java есть много встроенных классов, которые обеспечивают необходимую функциональность. Наиболее часто используемые находятся в основном пакете
java.lang
. Вы рассмотрите некоторые из них в этом разделе.Строковый класс
Класс
String
представляет комбинацию символов, составляющих строку. Чтобы объявитьString
или любую другую переменную ссылочного типа, вы сначала указываете ее тип, а затем ее имя. После этого вы присваиваете ему значение со знаком равенства. Пока это похоже на работу с примитивными типами. Однако ссылочные типы указывают на объекты, поэтому вам необходимо создать объект, если он еще не создан. Вот пример:String hello = new String("Hello");
hello
— это имя переменной со ссылочным типомString
. Вы назначаете его новому объектуString
. Новый объектString
создается с помощью ключевого словаnew
вместе с именем класса — в данном случаеString
. КлассString
начинается с заглавной буквы. По соглашению все классы и, следовательно, ссылочные типы начинаются с заглавной буквы.У каждого класса есть специальный метод, называемый конструктором, который используется для создания новых объектов. Вы можете вызвать этот конструктор, добавив круглые скобки (
()
) в конце имени класса. Конструктор может принимать параметры, как в приведенном выше примере, где параметрHello
применяется к конструктору дляString
.Чтобы убедиться, что переменная
hello
ведет себя должным образом, снова передайте ее методуprintln
следующим образом:- String hello = new String("Hello");
- System.out.println(hello);
Выполнение этих строк в
jshell
приведет к следующему выводу:Outputhello ==> "Hello" HelloНа этот раз выходные данные подтверждают, что для переменной
hello
установлено значениеHello
. После этого тот жеHello
печатается на новой строке, подтверждая, что методprintln()
его обработал.Классы-оболочки
В предыдущем разделе вы работали с часто используемым ссылочным типом
String
. Другими популярными ссылочными типами являются так называемые оболочки для примитивных типов. Класс-оболочка упаковывает или содержит примитивные данные, отсюда и его название. Все примитивные типы имеют аналоги-оболочки, и вот несколько примеров:Целое число
: для переноса значенийint
.Character
: для переноса значенийchar
.Boolean
: для переноса значенийboolean
.
Эти оболочки существуют для того, чтобы вы могли преобразовать простое примитивное значение в мощный объект. Каждая оболочка имеет готовые к использованию методы, связанные со значениями, которые она предназначена для хранения.
В качестве примера вы изучите
Integer
. В предыдущем разделе вы создали объектString
с ключевым словомnew
. Однако некоторые классы предоставляют и даже поощряют использование специальных методов для получения объектов от них, иInteger
является одним из них. В случаеInteger
использование специального метода в основном связано с оптимизацией ресурсов, но в других случаях речь может идти об упрощении построения сложных объектов.В следующем примере вы создаете переменную
Integer
с именемtheAnswer
со значением42
с помощью методаvalueOf
:- Integer theAnswer = Integer.valueOf(42);
- System.out.println(theAnswer);
В
jshell
вы получите следующий вывод:OutputtheAnswer ==> 42 42Вызывая метод
Integer
valueOf(42)
, вы указываете Java предоставить вам объект с этим значением. Незаметно Java проверит, есть ли уже объект с таким значением в его кеше. Если есть, объект будет связан с переменнойtheAnswer
. Если его нет, для переменнойtheAnswer
будет создан новый объект.Многие встроенные классы предоставляют такие методы из соображений производительности, и их использование рекомендуется, если не обязательно. В случае
Integer
вы все равно можете создать объект с ключевым словомnew
, но вы получите предупреждение об устаревании.В дополнение к
String
и оберткам существуют и другие полезные встроенные ссылочные типы, которые вы можете найти в сводке пакетов java.lang. Чтобы полностью понять некоторые из этих более сложных типов ссылок, требуется дополнительное объяснение или предварительные знания. Вот почему мы рассмотрим некоторые из них в наших следующих руководствах из серии Java.Литералы
Литералы представляют собой фиксированные значения, которые можно использовать непосредственно в коде и, таким образом, можно назначать как примитивным, так и ссылочным типам. Существует несколько типов литералов, которые можно классифицировать следующим образом.
Литералы примитивного типа
Вы уже использовали несколько литералов в разделе о примитивных типах. Для каждого примитивного типа существует литерал, например, из наших примеров:
42
,a
иtrue
. Целые числа, такие как42
, являются целочисленными литералами. Точно так же такие символы, какa
, являются символьными литералами, аtrue
иfalse
— булевыми литералами.Литералы примитивных типов также можно использовать для создания значений ссылочных типов. Литерал
int
использовался при создании объектаInteger
с кодомInteger.valueOf(42)
. Для этого также есть сокращение, и вы можете присвоить значение непосредственно следующим образом:Integer theAnswer = 42;
42
— это целочисленный литерал, как и любое целое число, и вы можете присвоить его непосредственно переменнойtheAnswer
без каких-либо дополнительных операторов. Часто можно увидеть, чтоInteger
объявляется таким образом, потому что это удобно.Этот сокращенный подход также работает для других литералов примитивных типов и их эквивалентных ссылочных типов, таких как
Boolean
, например:Boolean isFun = true;
true
— это литерал, который напрямую присваивается переменнойisFun
типаBoolean
. Существует также литералfalse
, который вы можете назначить таким же образом.Строковый литерал
Существует также специальный литерал для ссылочного типа
String
, и он распознается двойными кавычками, окружающими его значение. В этом примере этоHello, World!
:String helloWorld = "Hello, World!";
Использование литералов проще и короче, поэтому многие программисты предпочитают именно его. Однако вы по-прежнему можете объявить переменную
String
с новым объектомString
, как вы уже сделали в разделе для ссылочных типов.Нулевой литерал
Есть еще один важный литерал:
null
, который представляет отсутствие значения или несуществование объекта.Null
позволяет вам создать ссылочный тип и указать его наnull
вместо того, чтобы указывать на объект.null
можно использовать для всех ссылочных типов, но не для примитивных типов.С литералом
null
есть одно предостережение: вы можете объявлять с его помощью переменные, но вы не можете использовать эти переменные, пока не переназначите подходящее ненулевое значение. Если вы попытаетесь использовать переменную ссылочного типа со значениемnull
, вы получите сообщение об ошибке. Вот пример:- String initiallyNullString = null;
- System.out.println("The class name is: " + initiallyNullString.getClass());
Когда вы попытаетесь запустить этот код в
jshell
, вы увидите ошибку, похожую на следующую:OutputinitiallyNullString ==> null | Exception java.lang.NullPointerException | at (#4:1)В зависимости от вашей операционной системы и версии Java вывод может отличаться.
Ошибка
java.lang.NullPointerException
возникает из-за того, что вы пытаетесь вызвать методString
getClass()
(который возвращает имя класса ) в переменнойinitiallyNullString
(которая указывает на нулевой объект).Примечание. Для простоты мы называем
java.lang.NullPointerException
ошибкой, хотя технически это исключение. Дополнительные сведения об исключениях и ошибках см. в учебнике «Обработка исключений в Java».Чтобы устранить ошибку, вы должны переназначить значение
initiallyNullString
следующим образом:- String initiallyNullString = null;
- initiallyNullString = "not null any longer";
- System.out.println("The class name is: " + initiallyNullString.getClass());
Новый фиксированный код выведет следующий вывод:
OutputinitiallyNullString ==> null initiallyNullString ==> "not null any longer" The class name is: class java.lang.StringПриведенный выше вывод показывает, что
initiallyNullString
сначала являетсяnull
, а затем становится новым объектомString
, содержащимбольше не null
. Затем, когда методgetClass()
вызывается для созданного объекта, вы получаетеjava.lang.String
, в которомString
— это класс name иjava.lang
— его пакет. Наконец, выводится полное осмысленное сообщение:Имя класса: class java.lang.String
.Такие объявления значений
null
более распространены для устаревшего кода. Они использовались сначала для создания переменной, а затем для присвоения ее реального значения, обычно с использованием некоторой логики, определяющей последнее. Однако, начиная с версии Java 8, появился новый ссылочный тип, который называется Optional и больше подходит для случаев, когда ранее использовалсяnull
.Определение типа локальной переменной
До сих пор вы использовали некоторые распространенные типы данных в Java для определения переменных. Однако в Java 10 появилась новая функция под названием вывод типа локальной переменной, которая позволяет использовать ключевое слово
var
перед новой переменной. С помощью этой функции Java будет выводить (то есть автоматически угадывать) тип данных из локального контекста. Вывод типа является спорным, поскольку он контрастирует с ранее объясненной многословностью определения переменных. Преимущества и недостатки такой возможности спорны, но факт в том, что другие языки со статической типизацией, такие как C++, поддерживают вывод типов.В любом случае вывод типов не может полностью заменить использование типов данных, поскольку он работает только с локальными переменными, которые являются переменными внутри метода. Давайте посмотрим на пример с
var
:- var hello = "Hello";
- System.out.println(hello);
Вы объявляете переменную
hello
с помощью ключевого словаvar
, чтобы указать Java определить тип данных. После этого вы печатаете его на консоли обычным способом, чтобы убедиться, что он работает должным образом:Ouputhello ==> "Hello" HelloЭтот пример будет работать, если ваша установка Java (точнее, JDK) выше версии 10. Ключевое слово
var
не поддерживается в более ранних версиях.Вывод типа происходит в процессе компиляции, то есть когда вы компилируете код. Процесс компиляции превращает исходный текстовый код в машинный код и применяет различные оптимизации, включая определение типа. Это гарантирует, что правильный объем системной памяти доступен для переменных выводимого типа. Таким образом, машинный код, который вы запускаете после компиляции, полностью оптимизирован, как будто вы вручную указали все типы данных.
В этом примере ключевое слово
var
работает, поскольку переменная является локальной, а тип данныхvar
работает только с локальными переменными. Локальные переменные определяются внутри методов и доступны только внутри методов, поэтому они называются «локальными».Чтобы показать, что
var
можно использовать только для локальных переменных, попробуйте поместить его вне основного метода, например так:- public class Hello {
- var hello = "Hello";
- public static void main(String[] args) {
- // example code
- }
- }
Когда вы вставите приведенный выше код в
jshell
, вы получите следующую ошибку:Output| Error: | 'var' is not allowed here | var hello = "Hello"; | ^-^var
здесь недопустим, потому чтоhello
находится вне метода и больше не считается локальным. Таким образом, вывод типа не работает для нелокальных переменных, потому что контекст нельзя надежно использовать для определения типа данных.Хотя использование
var
может быть сложным и не обязательным, вы, скорее всего, столкнетесь с ним, поэтому полезно знать об этом.Зарезервированные ключевые слова
При объявлении переменных в Java нужно знать еще одно важное правило. Существуют зарезервированные ключевые слова, которые нельзя использовать для имен переменных. Например, вы не можете объявить примитив типа
int
и назвать егоnew
следующим образом:- int new = 1;
Если вы попробуете этот пример, вы получите ошибки компиляции, потому что
new
является зарезервированным ключевым словом.Output| Error: | '.class' expected | int new = 1; | ^ | Error: | <identifier> expected | int new = 1; | ^ | Error: | '(' or '[' expected | int new = 1; | ^ | Error: | unexpected type | required: value | found: class | int new = 1; | ^--^ | Error: | missing return statement | int new = 1; | ^----------^Ключевое слово
new
используется для создания новых объектов, и Java не ожидает его в этой позиции. В списке ошибок в предыдущем выводе первая часть самая важная:Output| Error: | '.class' expected | int new = 1; | ^Ошибка
.ожидаемый класс
означает, что когда вы используете ключевое словоnew
, Java ожидает, что за ним последует класс. В этот момент Java не может интерпретировать оператор, и следуют остальные ошибки.Остальные зарезервированные ключевые слова, такие как
abstract
,continue
,default
,for
иbreak
также имеют особое значение в Java и не могут использоваться для имен переменных. Полный список зарезервированных ключевых слов можно найти на странице Ключевые слова языка Java. Даже если вы не помните все зарезервированные ключевые слова, вы можете использовать ошибки компиляции для выявления проблемы.Заключение
В этом руководстве вы узнали о примитивных и ссылочных типах данных в Java, что является сложной, но важной темой. Не торопитесь, чтобы попрактиковаться и просмотреть примеры более одного раза. Попробуйте изменить некоторые типы данных и значения. Обратите внимание на то, когда возникают ошибки, а когда нет, чтобы выработать ощущение успешного выполнения кода.
Чтобы узнать больше о Java, ознакомьтесь с нашей серией статей How To Code in Java.