Поиск по сайту:

Понимание типов данных в 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:

    1. jshell

    Ваш вывод будет выглядеть примерно так:

    Output
    | Welcome to JShell -- Version 11.0.16 | For an introduction type: /help intro jshell>

    Вы можете вставить примеры кода из этого руководства в консоль. Когда вы закончите, вы можете выйти из jshell, набрав /exit.

    Чтобы объявить и использовать int, вставьте следующие строки в консоль jshell:

    1. int theAnswer = 42;
    2. System.out.println("The answer to all questions is " + theAnswer);

    Вы увидите следующий вывод:

    Output
    theAnswer ==> 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 следующим образом:

    1. boolean isJavaFun = true;
    2. System.out.println("Java is fun: " + isJavaFun);

    Выполнение этих строк в jshell приведет к следующему выводу:

    Output
    isJavaFun ==> 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 следующим образом:

    1. String hello = new String("Hello");
    2. System.out.println(hello);

    Выполнение этих строк в jshell приведет к следующему выводу:

    Output
    hello ==> "Hello" Hello

    На этот раз выходные данные подтверждают, что для переменной hello установлено значение Hello. После этого тот же Hello печатается на новой строке, подтверждая, что метод println() его обработал.

    Классы-оболочки

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

    • Целое число: для переноса значений int.
    • Character: для переноса значений char.
    • Boolean: для переноса значений boolean.

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

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

    В следующем примере вы создаете переменную Integer с именем theAnswer со значением 42 с помощью метода valueOf:

    1. Integer theAnswer = Integer.valueOf(42);
    2. System.out.println(theAnswer);

    В jshell вы получите следующий вывод:

    Output
    theAnswer ==> 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, вы получите сообщение об ошибке. Вот пример:

    1. String initiallyNullString = null;
    2. System.out.println("The class name is: " + initiallyNullString.getClass());

    Когда вы попытаетесь запустить этот код в jshell, вы увидите ошибку, похожую на следующую:

    Output
    initiallyNullString ==> null | Exception java.lang.NullPointerException | at (#4:1)

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

    Ошибка java.lang.NullPointerException возникает из-за того, что вы пытаетесь вызвать метод String getClass() (который возвращает имя класса ) в переменной initiallyNullString (которая указывает на нулевой объект).

    Примечание. Для простоты мы называем java.lang.NullPointerException ошибкой, хотя технически это исключение. Дополнительные сведения об исключениях и ошибках см. в учебнике «Обработка исключений в Java».

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

    1. String initiallyNullString = null;
    2. initiallyNullString = "not null any longer";
    3. System.out.println("The class name is: " + initiallyNullString.getClass());

    Новый фиксированный код выведет следующий вывод:

    Output
    initiallyNullString ==> 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:

    1. var hello = "Hello";
    2. System.out.println(hello);

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

    Ouput
    hello ==> "Hello" Hello

    Этот пример будет работать, если ваша установка Java (точнее, JDK) выше версии 10. Ключевое слово var не поддерживается в более ранних версиях.

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

    В этом примере ключевое слово var работает, поскольку переменная является локальной, а тип данных var работает только с локальными переменными. Локальные переменные определяются внутри методов и доступны только внутри методов, поэтому они называются «локальными».

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

    1. public class Hello {
    2. var hello = "Hello";
    3. public static void main(String[] args) {
    4. // example code
    5. }
    6. }

    Когда вы вставите приведенный выше код в jshell, вы получите следующую ошибку:

    Output
    | Error: | 'var' is not allowed here | var hello = "Hello"; | ^-^

    var здесь недопустим, потому что hello находится вне метода и больше не считается локальным. Таким образом, вывод типа не работает для нелокальных переменных, потому что контекст нельзя надежно использовать для определения типа данных.

    Хотя использование var может быть сложным и не обязательным, вы, скорее всего, столкнетесь с ним, поэтому полезно знать об этом.

    Зарезервированные ключевые слова

    При объявлении переменных в Java нужно знать еще одно важное правило. Существуют зарезервированные ключевые слова, которые нельзя использовать для имен переменных. Например, вы не можете объявить примитив типа int и назвать его new следующим образом:

    1. 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.