Jump to content

Синтаксис Java

(Перенаправлено с ключевого слова Java )
Фрагмент кода Java с ключевыми словами, выделенными жирным синим шрифтом.

Синтаксис Java — это набор правил , определяющих, как Java пишется и интерпретируется программа .

Синтаксис в основном заимствован из C и C++ . В отличие от C++, в Java нет глобальных функций или переменных, но есть элементы данных, которые также считаются глобальными переменными . Весь код принадлежит классам , а все значения являются объектами . Единственным исключением являются примитивные типы , которые не считаются объектами из соображений производительности (хотя могут быть автоматически преобразованы в объекты и наоборот посредством автоупаковки ). Некоторые функции, такие как перегрузка операторов или целочисленные типы без знака, опущены, чтобы упростить язык и избежать возможных ошибок программирования.

Синтаксис Java постепенно расширялся в ходе многочисленных крупных JDK выпусков и теперь поддерживает такие возможности, как универсальное программирование и функциональные литералы (называемые лямбда-выражениями в Java). С 2017 года новая версия JDK выпускается два раза в год, причем каждый выпуск вносит в язык дополнительные улучшения.

Идентификатор

[ редактировать ]

Идентификатор это имя элемента в коде . Существуют определенные стандартные соглашения об именах , которым следует следовать при выборе имен для элементов. Идентификаторы в Java чувствительны к регистру .

Идентификатор может содержать:

  • Любой символ Юникода, являющийся буквой (включая цифровые буквы, например римские цифры ) или цифрой.
  • Знак валюты (например, ¥).
  • Соединительный знак пунктуации (например , _ ).

Идентификатор не может:

  • Начните с цифры.
  • Быть равным зарезервированному ключевому слову, нулевому или логическому литералу.

Ключевые слова

[ редактировать ]
абстрактный продолжать для новый выключатель
утверждать по умолчанию перейти к упаковка синхронизированный
логическое значение делать если частный этот
перерыв двойной реализует защищенный бросать
байт еще импортировать общественный бросает
случай перечисление экземпляр возвращаться преходящий
ловить простирается интервал короткий пытаться
голец финальный интерфейс статический наш
сорт окончательно длинный строгийfp пустота
константа плавать родной супер изменчивый
пока

Литералы

[ редактировать ]
Целые числа
двоичный (введен в Java SE 7) 0b11110101 ( 0b, за которым следует двоичное число)
восьмеричный 0365 ( 0, за которым следует восьмеричное число)
шестнадцатеричный 0xF5 ( 0x, за которым следует шестнадцатеричное число)
десятичный 245 (десятичное число)
с плавающей запятой Значения
плавать 23,5Ф , .5f , 1,72E3F (десятичная дробь с дополнительным индикатором степени, за которой следует Ф )
0x.5FP0F , 0x.5P-6f ( 0x, за которым следует шестнадцатеричная дробь с обязательным индикатором степени и суффиксом. Ф )
двойной 23,5Д , .5 , 1,72E3D (десятичная дробь с необязательным индикатором степени, за которым следует необязательный Д )
0x.5FP0 , 0x.5P-6D ( 0x, за которым следует шестнадцатеричная дробь с обязательным индикатором степени и необязательным суффиксом. Д )
Символьные литералы
голец 'а' , 'С' , '\u0231' (символ или escape-символ, заключенный в одинарные кавычки)
Логические литералы
логическое значение истинный , ЛОЖЬ
нулевой литерал
нулевая ссылка нулевой
Строковые литералы
Нить «Hello, World» (последовательность символов и escape-символов, заключенная в двойные кавычки)
Символы экранируются в строках
Юникода Символ \u3876 ( \u , за которым следует шестнадцатеричный код Юникода до U+FFFF)
Восьмеричный побег \352 (восьмеричное число, не превышающее 377, которому предшествует обратная косая черта)
Перевод строки \п
Возврат каретки
Подача формы \ е
обратная косая черта \\
Одиночная цитата \'
Двойная кавычка \"
Вкладка \ т
Backspace

Целочисленные литералы имеют int введите по умолчанию, если только long тип указывается добавлением L или l суффикс к буквальному, например 367L. Начиная с Java SE 7, между цифрами числа можно включать подчеркивания для повышения читабельности; например, число 145608987 можно записать как 145_608_987 .

Переменные

[ редактировать ]

Переменные — это идентификаторы, связанные со значениями. Они объявляются путем записи типа и имени переменной и при необходимости инициализируются в том же операторе путем присвоения значения.

int count;      //Declaring an uninitialized variable called 'count', of type 'int'
count = 35;     //Initializing the variable
int count = 35; //Declaring and initializing the variable at the same time

Несколько переменных одного типа могут быть объявлены и инициализированы в одном операторе, используя запятую в качестве разделителя.

int a, b;         //Declaring multiple variables of the same type
int a = 2, b = 3; //Declaring and initializing multiple variables of the same type

Вывод типа

[ редактировать ]

Начиная с Java 10, стало возможным автоматически определять типы переменных, используя var.

// stream will have the FileOutputStream type as inferred from its initializer
var stream = new FileOutputStream("file.txt");

// An equivalent declaration with an explicit type
FileOutputStream stream = new FileOutputStream("file.txt");

Блоки кода

[ редактировать ]

Сепараторы { и } обозначают блок кода и новую область действия. Члены класса и тело метода являются примерами того, что может находиться внутри этих фигурных скобок в различных контекстах.

Внутри тел методов можно использовать фигурные скобки для создания новых областей следующим образом:

void doSomething() {
    int a;

    {
        int b;
        a = 1;
    }

    a = 2;
    b = 3; // Illegal because the variable b is declared in an inner scope..
}

Комментарии

[ редактировать ]

В Java есть три типа комментариев : традиционные комментарии , комментарии в конце строки и комментарии к документации .

Традиционные комментарии, также известные как блочные комментарии, начинаются с /* и закончить на */, они могут занимать несколько строк. Этот тип комментариев был получен из C и C++.

/* This is a multi-line comment.
It may occupy more than one line. */

Комментарии в конце строки начинаются с // и продлиться до конца текущей строки. Этот тип комментариев также присутствует в C++ и современном C.

// This is an end-of-line comment

Комментарии к документации в исходных файлах обрабатываются инструментом Javadoc для создания документации. Этот тип комментариев идентичен традиционным комментариям, за исключением того, что он начинается с /** и следует соглашениям, определенным инструментом Javadoc. Технически эти комментарии представляют собой особый вид традиционных комментариев и не определены конкретно в спецификации языка.

/**
 * This is a documentation comment.
 * 
 * @author John Doe
 */

Универсальные типы

[ редактировать ]

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

java.lang.Объект

[ редактировать ]

java.lang.Object Java является высшим типом . Суперкласс всех классов, у которых не объявлен родительский класс. Все значения могут быть преобразованы в этот тип, хотя для примитивных значений это предполагает автоупаковку .

java.lang.String

[ редактировать ]

java.lang.String это базовый строковый тип Java. Неизменяемый . Некоторые методы рассматривают каждую единицу кода UTF-16 как «символ», но методы преобразования в int[] то есть, по сути, UTF-32 также доступен .

java.lang.Throwable

[ редактировать ]

java.lang.Throwable это супертип всего, что можно бросить или поймать с помощью Java throw и catch заявления.

Структура программы

[ редактировать ]

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

main метод

[ редактировать ]

Каждое Java-приложение должно иметь точку входа. Это справедливо как для приложений с графическим интерфейсом, так и для консольных приложений. Точкой входа является main метод. Может быть более одного класса с main метод, но основной класс всегда определяется извне (например, в файле манифеста ). main метод вместе с основным классом должен быть объявлен public. Метод должен быть static и передается аргументы командной строки в виде массива строк. В отличие от C++ или C# , он никогда не возвращает значение и должен возвращать void.

public static void main(String[] args) {
}

Пакеты являются частью имени класса и используются для группировки и/или отличия именованных объектов от других. Другая цель пакетов — управлять доступом к коду вместе с модификаторами доступа. Например, java.io.InputStream это полное имя класса для класса InputStream который находится в упаковке java.io.

Пакет объявляется в начале файла с помощью package декларация:

package myapplication.mylibrary;

public class MyClass {
}

Занятия с public модификатор необходимо размещать в файлах с таким же именем и java и поместить во вложенные папки, соответствующие имени пакета. Вышеупомянутый класс myapplication.mylibrary.MyClass будет иметь следующий путь: myapplication/mylibrary/MyClass.java.

Импортная декларация

[ редактировать ]

Тип импортной декларации

[ редактировать ]

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

package myPackage;

import java.util.Random; // Single type declaration

public class ImportsTest {
    public static void main(String[] args) {
        /* The following line is equivalent to
         * java.util.Random random = new java.util.Random();
         * It would've been incorrect without the import.
         */
        Random random = new Random();
    }
}

В коде упоминаются объявления импорта по требованию. «Импорт типа» импортирует все типы пакета. «Статический импорт» импортирует члены пакета.

import java.util.*;  /*This form of importing classes makes all classes
    in package java.util available by name, could be used instead of the
    import declaration in the previous example. */
import java.*; /*This statement is legal, but does nothing, since there
    are no classes directly in package java. All of them are in packages
    within package java. This does not import all available classes.*/

Статическая импортная декларация

[ редактировать ]

Этот тип объявления доступен начиная с J2SE 5.0 . Объявления статического импорта позволяют получить доступ к статическим членам, определенным в другом классе, интерфейсе, аннотации или перечислении; без указания имени класса:

import static java.lang.System.out; //'out' is a static field in java.lang.System

public class HelloWorld {
    public static void main(String[] args) {
        /* The following line is equivalent to
             System.out.println("Hi World!");
           and would have been incorrect without the import declaration. */
        out.println("Hello World!");
    }
}

Объявления импорта по требованию позволяют импортировать все поля типа:

import static java.lang.System.*;
    /* This form of declaration makes all
       fields in the java.lang.System class available by name, and may be used instead
       of the import declaration in the previous example. */

Константы перечисления также можно использовать при статическом импорте. Например, это перечисление находится в пакете с именем screen:

public enum ColorName {
    RED, BLUE, GREEN
};

Можно использовать статические объявления импорта в другом классе для получения констант перечисления:

import screen.ColorName;
import static screen.ColorName.*;

public class Dots {
    /* The following line is equivalent to 'ColorName foo = ColorName.RED',
       and it would have been incorrect without the static import. */
    ColorName foo = RED;

    void shift() {
        /* The following line is equivalent to
           if (foo == ColorName.RED) foo = ColorName.BLUE; */
        if (foo == RED) foo = BLUE;
    }
}

Операторы

[ редактировать ]

Операторы в Java аналогичны операторам в C++ . Однако нет delete оператор из-за механизмов сборки мусора отсутствуют, в Java, а операции с указателями поскольку Java их не поддерживает. Еще одно отличие состоит в том, что в Java есть беззнаковый оператор сдвига вправо ( >>>), тогда как знаковость оператора сдвига вправо в C зависит от типа. Операторы в Java не могут быть перегружены .

Приоритет Оператор Описание Ассоциативность
1 () Вызов метода Слева направо
[] Доступ к массиву
. Выбор участника класса
2 ++ -- Постфиксное приращение и декремент [ 1 ]
3 ++ -- Увеличение и уменьшение префикса Справа налево
+ - Унарный плюс и минус
! ~ Логическое НЕ и побитовое НЕ.
(type) val Тип актерского состава
new Создание экземпляра класса или массива
4 * / % Умножение, деление и модуль (остаток) Слева направо
5 + - Сложение и вычитание
+ Конкатенация строк
6 << >> >>> Побитовый сдвиг влево, знаковый сдвиг вправо и беззнаковый сдвиг вправо.
7 < <= Относительные «меньше чем» и «меньше или равно»
> >= Относительные «больше» и «больше или равно»
instanceof Сравнение типов
8 == != Относительные «равно» и «не равно».
9 & Побитовое и логическое И
10 ^ Побитовое и логическое исключающее ИЛИ (исключающее или)
11 | Побитовое и логическое ИЛИ (включающее или)
12 && Логическое условное И
13 || Логическое условное ИЛИ
14 c ? t : f Тернарное условное выражение (см. ?: ) Справа налево
15 = Простое задание
+= -= Присваивание по сумме и разности
*= /= %= Присваивание по произведению, частному и остатку
<<= >>= >>>= Назначение побитовым сдвигом влево, знаковым сдвигом вправо и беззнаковым сдвигом вправо.
&= ^= |= Присваивание с помощью побитового И, исключающего ИЛИ и ИЛИ.

Структуры управления

[ редактировать ]

Условные операторы

[ редактировать ]

if заявление

[ редактировать ]

Операторы if в Java аналогичны операторам C и используют тот же синтаксис:

if (i == 3) {
    doSomething();
}

if оператор может включать необязательный else блок, и в этом случае он становится оператором if-then-else:

if (i == 3) {
    doSomething();
} else {
    doSomethingElse();
}

Как и в языке C, конструкция else-if не требует каких-либо специальных ключевых слов, она формируется как последовательность отдельных операторов if-then-else:

if (i == 3) {
    doSomething();
} else if (i == 2) {
    doSomethingElse();
} else {
    doSomethingDifferent();
}

Также обратите внимание, что оператор ?: можно использовать вместо простого оператора if, например

int a = 1;
int b = 2;
int minVal = (a < b) ? a : b;

switch заявление

[ редактировать ]

Операторы переключения в Java могут использовать byte, short, char, и int (примечание: нет long) примитивные типы данных или соответствующие им типы-оболочки. Начиная с J2SE 5.0, можно использовать типы перечислений . Начиная с Java SE 7, можно использовать строки. [ 2 ] Другие типы ссылок нельзя использовать в switch заявления.

Возможные значения перечислены с помощью case этикетки. Эти метки в Java могут содержать только константы (включая константы перечисления и строковые константы). Выполнение начнется после метки, соответствующей выражению внутри скобок. Дополнительный default метка может присутствовать, чтобы объявить, что следующий за ней код будет выполнен, если ни одна из меток регистра не соответствует выражению.

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

switch (ch) {
    case 'A':
        doSomething(); // Triggered if ch == 'A'
        break;
    case 'B':
    case 'C':
        doSomethingElse(); // Triggered if ch == 'B' or ch == 'C'
        break;
    default:
        doSomethingDifferent(); // Triggered in any other case
        break;
}
switch выражения
[ редактировать ]

Начиная с Java 14 стало возможным использовать выражения переключения, которые используют новый синтаксис стрелок:

var result = switch (ch) {
    case 'A' -> Result.GREAT;
    case 'B', 'C' -> Result.FINE;
    default -> throw new ThisIsNoGoodException();
};

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

var result = switch (ch) {
    case 'A':
        yield Result.GREAT;
    case 'B':
    case 'C':
        yield Result.FINE;
    default:
        throw new ThisIsNoGoodException();
};

Операторы итерации

[ редактировать ]

Операторы итерации — это операторы, которые выполняются повторно, когда заданное условие оценивается как истинное. Начиная с J2SE 5.0 , в Java есть четыре формы таких операторов. Обратите внимание, что условие должно иметь тип boolean или Boolean, что означает C.

while (1) {
    doSomething();
}

приводит к ошибке компиляции.

while петля

[ редактировать ]

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

while (i < 10) {
    doSomething();
}

do ... while петля

[ редактировать ]

В do ... while цикле тест выполняется после каждой итерации. Следовательно, код всегда выполняется хотя бы один раз.

// doSomething() is called at least once
do {
    doSomething();
} while (i < 10);

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

for (int i = 0; i < 10; i++) {
    doSomething();
}
 
// A more complex loop using two variables
for (int i = 0, j = 9; i < 10; i++, j -= 3) {
    doSomething();
}

Как и в C, все три выражения являются необязательными. Следующий цикл бесконечен:

for (;;) {
    doSomething();
}

Улучшенный for петля

[ редактировать ]

Улучшенный for циклы доступны начиная с J2SE 5.0 . Этот тип цикла использует встроенные итераторы для массивов и коллекций для возврата каждого элемента в данной коллекции. Каждый элемент возвращается и доступен в контексте блока кода. Когда блок выполняется, следующий элемент возвращается до тех пор, пока элементов не останется. В отличие от C# , этот тип цикла не требует специального ключевого слова, а использует другой стиль записи.

for (int i : intArray) {
    doSomething(i);
}

Операторы перехода

[ редактировать ]

Этикетки

[ редактировать ]

Меткам присваиваются точки в коде, используемом break и continue заявления. Обратите внимание, что Java goto Ключевое слово нельзя использовать для перехода к определенным точкам кода.

start:
someMethod();

break заявление

[ редактировать ]

The break оператор выходит из ближайшего цикла или switch заявление. Выполнение продолжается в операторе после прерванного оператора, если таковой имеется.

for (int i = 0; i < 10; i++) {
    while (true) {
        break;
    }
    // Will break to this point
}

Выйти из внешнего цикла можно с помощью меток:

outer:
for (int i = 0; i < 10; i++) {
    while (true) {
        break outer;
    }
}
// Will break to this point

continue заявление

[ редактировать ]

The continue Оператор прекращает текущую итерацию текущего оператора управления и начинает следующую итерацию. Следующее while цикл в приведенном ниже коде считывает символы, вызывая getChar(), пропуская операторы в теле цикла, если символы являются пробелами:

int ch;
while (ch == getChar()) {
    if (ch == ' ') {
        continue; // Skips the rest of the while-loop
    }

    // Rest of the while-loop, will not be reached if ch == ' '
    doSomething();
}

Метки могут быть указаны в continue заявления и break заявления:

outer:
for (String str : stringsArr) {
    char[] strChars = str.toCharArray();
    for (char ch : strChars) {
        if (ch == ' ') {
            /* Continues the outer cycle and the next
            string is retrieved from stringsArr */
            continue outer;
        }
        doSomething(ch);
    }
}

return заявление

[ редактировать ]

The return Оператор используется для завершения выполнения метода и возврата значения. Значение, возвращаемое методом, записывается после return ключевое слово. Если метод возвращает что-либо, кроме void, он должен использовать return оператор, возвращающий некоторое значение.

void doSomething(boolean streamClosed) {
    // If streamClosed is true, execution is stopped
    if (streamClosed) {
        return;
    }
    readFromStream();
}

int calculateSum(int a, int b) {
    int result = a + b;
    return result;
}

return оператор немедленно завершает выполнение, за исключением одного случая: если оператор встречается внутри try блок и дополняется finally, управление передается finally блокировать.

void doSomething(boolean streamClosed) {
    try {
        if (streamClosed) {
            return;
        }
        readFromStream();
    } finally {
        /* Will be called last even if 
        readFromStream() was not called */
        freeResources();
    }
}

Операторы обработки исключений

[ редактировать ]

try-catch-finally заявления

[ редактировать ]

Исключения управляются внутри try ... catch блоки.

try {
    // Statements that may throw exceptions
    methodThrowingExceptions();
} catch (Exception ex) {
    // Exception caught and handled here
    reportException(ex);
} finally {
    // Statements always executed after the try/catch blocks
    freeResources();
}

Заявления в рамках try блок выполняются, и если какой-либо из них генерирует исключение, выполнение блока прекращается, и исключение обрабатывается catch блокировать. Может быть несколько catch блоков, в этом случае выполняется первый блок с переменной исключения, тип которой соответствует типу выброшенного исключения.

В Java SE 7 помимо предложений uni-catch также появились предложения с несколькими перехватами. Этот тип предложений catch позволяет Java обрабатывать различные типы исключений в одном блоке, при условии, что они не являются подклассами друг друга.

try {
    methodThrowingExceptions();
} catch (IOException | IllegalArgumentException ex) {
    //Both IOException and IllegalArgumentException will be caught and handled here
    reportException(ex);
}

Если нет catch соответствует типу выброшенного исключения, выполнение внешнего блока (или метода), содержащего try ... catch оператор прекращается, и исключение передается за пределы содержащего его блока (или метода). Исключение распространяется вверх по стеку вызовов до тех пор, пока не будет найдено соответствующее исключение. catch блок находится в одном из активных в данный момент методов. Если исключение распространяется до самого верхнего main метод без сопоставления catch При обнаружении блока текстовое описание исключения записывается в стандартный поток вывода.

Заявления в рамках finally блок всегда выполняется после try и catch блоков, независимо от того, было ли выдано исключение и даже если return заявление было достигнуто. Такие блоки полезны для предоставления кода очистки, который гарантированно всегда будет выполняться.

The catch и finally блоки не являются обязательными, но хотя бы один или другой должен присутствовать после try блокировать.

tryзаявления с ресурсами

[ редактировать ]

tryОператоры -with-resources представляют собой особый тип try-catch-finally операторы, представленные как реализация шаблона удаления в Java SE 7. В try-with-resources заявление try за ключевым словом следует инициализация одного или нескольких ресурсов, которые освобождаются автоматически при try выполнение блока завершено. Ресурсы должны реализовать java.lang.AutoCloseable. tryОператоры -with-resources не обязаны иметь catch или finally блокировать в отличие от обычного try-catch-finally заявления.

try (FileOutputStream fos = new FileOutputStream("filename");
    XMLEncoder xEnc = new XMLEncoder(fos)) {
    xEnc.writeObject(object);
} catch (IOException ex) {
    Logger.getLogger(Serializer.class.getName()).log(Level.SEVERE, null, ex);
}

Начиная с Java 9 можно использовать уже объявленные переменные:

FileOutputStream fos = new FileOutputStream("filename");
XMLEncoder xEnc = new XMLEncoder(fos);
try (fos; xEnc) {
    xEnc.writeObject(object);
} catch (IOException ex) {
    Logger.getLogger(Serializer.class.getName()).log(Level.SEVERE, null, ex);
}

throw заявление

[ редактировать ]

The throw Оператор используется для создания исключения и завершения выполнения блока или метода. Выброшенный экземпляр исключения записывается после throw заявление.

void methodThrowingExceptions(Object obj) {
    if (obj == null) {
        // Throws exception of NullPointerException type
        throw new NullPointerException();
    }
    // Will not be called, if object is null
    doSomethingWithObject(obj);
}

Управление параллелизмом потоков

[ редактировать ]

Java имеет встроенные инструменты для многопоточного программирования . В целях синхронизации потоков synchronized оператор включен в язык Java.

Чтобы синхронизировать блок кода, ему предшествует synchronized ключевое слово, за которым следует объект блокировки внутри скобок. Когда исполняющий поток достигает синхронизированного блока, он получает блокировку взаимного исключения , выполняет блок, а затем снимает блокировку. Ни один поток не может войти в этот блок, пока блокировка не будет снята. В качестве блокировки можно использовать любой ссылочный тип, отличный от NULL.

/* Acquires lock on someObject. It must be of
a reference type and must be non-null */
synchronized (someObject) {
    // Synchronized statements
}

assert заявление

[ редактировать ]

assert операторы доступны начиная с J2SE 1.4 . Эти типы операторов используются для создания утверждений в исходном коде, которые можно включать и выключать во время выполнения для определенных классов или пакетов. Чтобы объявить утверждение assert используется ключевое слово, за которым следует условное выражение. Если он оценивается как false при выполнении оператора выдается исключение. Этот оператор может включать двоеточие, за которым следует другое выражение, которое будет действовать как подробное сообщение об исключении.

// If n equals 0, AssertionError is thrown
assert n != 0;
/* If n equals 0, AssertionError will be thrown
with the message after the colon */
assert n != 0 : "n was equal to zero";

Примитивные типы

[ редактировать ]

Примитивные типы в Java включают целочисленные типы, числа с плавающей запятой, кодовые единицы UTF-16 и логический тип. В Java нет беззнаковых типов, кроме char тип, который используется для представления кодовых единиц UTF-16. Отсутствие беззнаковых типов компенсируется введением беззнаковой операции сдвига вправо ( >>>), которого нет в C++. Тем не менее, высказывалась критика по поводу связанной с этим несовместимости с C и C++. [ 3 ]

Примитивные типы
Тип Имя Класс-оболочка Ценить Диапазон Размер Значение по умолчанию
byte java.lang.Byte целое число от −128 до +127 8-битный (1-байтовый) 0
short java.lang.Short целое число от −32 768 до +32 767 16 бит (2 байта) 0
int java.lang.Integer целое число от −2 147 483 648 до +2 147 483 647 32-битный (4-байтовый) 0
long java.lang.Long целое число −9 223 372 036 854 775 808 через
+9,223,372,036,854,775,807
64-битный (8-байтовый) 0
float java.lang.Float число с плавающей запятой от ±1,401298E−45 до ±3,402823E+38 32-битный (4-байтовый) 0.0f[ 4 ]
double java.lang.Double число с плавающей запятой ±4,94065645841246E-324 через
±1,79769313486232E+308
64-битный (8-байтовый) 0.0
boolean java.lang.Boolean логическое значение true или false 1-bit (1-bit) false
char java.lang.Character UTF-16 Кодовая единица BMP ( символ
или часть суррогатной пары)
'\u0000' через '\uFFFF' 16 бит (2 байта) '\u0000'

char не обязательно соответствует одному символу. Он может представлять собой часть суррогатной пары , и в этом случае кодовая точка Юникода представлена ​​последовательностью двух char ценности.

Упаковка и распаковка

[ редактировать ]

Эта языковая функция была представлена ​​в J2SE 5.0 . Упаковка — это операция преобразования значения примитивного типа в значение соответствующего ссылочного типа, которая служит оберткой для этого конкретного примитивного типа. Распаковка — это обратная операция преобразования значения ссылочного типа (ранее упакованного) в значение соответствующего примитивного типа. Ни одна из операций не требует явного преобразования.

Пример:

int foo = 42; // Primitive type
Integer bar = foo; /* foo is boxed to bar, bar is of Integer type,
                      which serves as a wrapper for int */
int foo2 = bar; // Unboxed back to primitive type

Типы ссылок

[ редактировать ]

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

Ссылочная переменная — это null когда он не ссылается ни на один объект.

Массивы в Java создаются во время выполнения, как и экземпляры классов. Длина массива определяется при создании и не может быть изменена.

int[] numbers = new int[5];
numbers[0] = 2;
numbers[1] = 5;
int x = numbers[0];

Инициализаторы

[ редактировать ]
// Long syntax
int[] numbers = new int[] {20, 1, 42, 15, 34};
// Short syntax
int[] numbers2 = {20, 1, 42, 15, 34};

Многомерные массивы

[ редактировать ]

В Java многомерные массивы представлены как массивы массивов. Технически они представлены массивами ссылок на другие массивы.

int[][] numbers = new int[3][3];
numbers[1][2] = 2;

int[][] numbers2 = {{2, 3, 2}, {1, 2, 6}, {2, 4, 5}};

Из-за природы многомерных массивов длина подмассивов может различаться, поэтому многомерные массивы не обязательно должны быть прямоугольными, в отличие от C:

int[][] numbers = new int[2][]; //Initialization of the first dimension only

numbers[0] = new int[3];
numbers[1] = new int[2];

Классы — это основа объектно-ориентированного языка, такого как Java. Они содержат элементы, которые хранят данные и манипулируют ими. Классы делятся на верхнего уровня и вложенные . Вложенные классы — это классы, помещенные внутри другого класса, которые могут обращаться к закрытым членам включающего класса. Вложенные классы включают классы-члены (которые могут быть определены с модификатором static для простой вложенности или без него для внутренних классов), локальные классы и анонимные классы .

Декларация

[ редактировать ]
Класс высшего уровня
class Foo {
    // Class members
}
Внутренний класс
class Foo { // Top-level class
    class Bar { // Inner class
    }
}
Вложенный класс
class Foo { // Top-level class
    static class Bar { // Nested class
    }
}
Местный класс
class Foo {
    void bar() {
        class Foobar {// Local class within a method
        }
    }
}
Анонимный класс
class Foo {
    void bar() {
        new Object() {// Creation of a new anonymous class extending Object
        };
    }
}

Создание экземпляра

[ редактировать ]

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

Foo foo = new Foo();

Доступ к участникам

[ редактировать ]

Доступ к членам как экземпляров, так и статических классов осуществляется с помощью . (точка) оператор.

Доступ к члену экземпляра
Доступ к членам экземпляра можно получить через имя переменной.

String foo = "Hello";
String bar = foo.toUpperCase();

Доступ к статическому члену класса
Доступ к статическим членам осуществляется с использованием имени класса или любого другого типа. Для этого не требуется создание экземпляра класса. Статические члены объявляются с использованием static модификатор.

public class Foo {
    public static void doSomething() {
    }
}

// Calling the static method
Foo.doSomething();

Модификаторы

[ редактировать ]

Модификаторы — это ключевые слова, используемые для изменения объявлений типов и членов типов. В частности, существует подгруппа, содержащая модификаторы доступа.

  • abstract — Указывает, что класс служит только базовым классом и не может быть создан.
  • static — Используется только для классов-членов. Указывает, что класс-член не принадлежит конкретному экземпляру содержащего его класса.
  • final - Классы, отмеченные как final не может быть расширен и не может иметь подклассов.
  • strictfp - Указывает, что все операции с плавающей запятой должны выполняться в соответствии со стандартом IEEE 754 , и запрещает использование повышенной точности для хранения промежуточных результатов.
Абстрактный класс
[ редактировать ]

По умолчанию все методы во всех классах являются конкретными, если не используется ключевое слово Abstract. Абстрактный класс может включать в себя абстрактные методы, не имеющие реализации. По умолчанию все методы во всех интерфейсах являются абстрактными, если не используется ключевое слово default. Ключевое слово по умолчанию можно использовать для указания конкретного метода в интерфейсе.

//By default, all methods in all classes are concrete, unless the abstract keyword is used.
public abstract class Demo {
    // An abstract class may include abstract methods, which have no implementation.
    public abstract int sum(int x, int y);

    // An abstract class may also include concrete methods.
    public int product(int x, int y) { 
        return x*y; 
    }
}

//By default, all methods in all interfaces are abstract, unless the default keyword is used.
interface DemoInterface {
    int getLength(); //The abstract keyword can be used here, though is completely useless
    
    //The default keyword can be used in this context to specify a concrete method in an interface
    default int product(int x, int y) {
        return x * y;
    }
}
Заключительный урок
[ редактировать ]

Последний класс не может быть подклассом. Поскольку это может обеспечить преимущества в безопасности и эффективности, многие классы стандартной библиотеки Java являются окончательными, например: java.lang.System и java.lang.String.

Пример:

public final class MyFinalClass {...}

public class ThisIsWrong extends MyFinalClass {...} // forbidden
Модификаторы доступа
[ редактировать ]

Модификаторы доступа или модификаторы наследования задают доступность классов, методов и других членов. Участники отмечены как public можно добраться откуда угодно. Если у класса или его члена нет модификаторов, предполагается доступ по умолчанию.

public class Foo {
    int go() {
        return 0;
    }

    private class Bar {
    }
}

В следующей таблице показано, имеет ли код внутри класса доступ к классу или методу в зависимости от местоположения класса доступа и модификатора доступного класса или члена класса:

Модификатор Тот же класс или вложенный класс Другой класс внутри того же пакета Расширенный класс внутри другого пакета Нерасширенный внутри другого пакета
private да нет нет нет
по умолчанию (частный пакет) да да нет нет
protected да да да нет
public да да да да
Это изображение описывает область действия члена класса внутри классов и пакетов.

Конструкторы и инициализаторы

[ редактировать ]

Конструктор — это специальный метод , вызываемый при инициализации объекта. Его цель — инициализировать члены объекта. Основные различия между конструкторами и обычными методами заключаются в том, что конструкторы вызываются только при создании экземпляра класса и никогда ничего не возвращают. Конструкторы объявляются как общие методы, но они названы в честь класса и не указан тип возвращаемого значения:

class Foo {
    String str;

    Foo() { // Constructor with no arguments

        // Initialization
    }

    Foo(String str) { // Constructor with one argument
        this.str = str;
    }
}

Инициализаторы — это блоки кода, которые выполняются при создании класса или экземпляра класса. Существует два типа инициализаторов: статические инициализаторы и инициализаторы экземпляров .

Статические инициализаторы инициализируют статические поля при создании класса. Они объявляются с использованием static ключевое слово:

class Foo {
    static {
        // Initialization
    }
}

Класс создается только один раз. Поэтому статические инициализаторы не вызываются более одного раза. Напротив, инициализаторы экземпляров автоматически вызываются перед вызовом конструктора каждый раз, когда создается экземпляр класса. В отличие от конструкторов, инициализаторы экземпляров не могут принимать никаких аргументов и, как правило, не могут генерировать проверенные исключения (за исключением нескольких особых случаев). Инициализаторы экземпляров объявляются в блоке без каких-либо ключевых слов:

class Foo {
    {
        // Initialization
    }
}

нет Поскольку в Java есть механизм сборки мусора, деструкторов . Однако каждый объект имеет finalize() метод, вызываемый перед сборкой мусора, который можно переопределить для реализации финализации.

Все операторы в Java должны находиться внутри методов. Методы аналогичны функциям, за исключением того, что они принадлежат классам. Метод имеет возвращаемое значение, имя и обычно некоторые параметры, инициализируемые при его вызове с некоторыми аргументами. Подобно C++, методы, ничего не возвращающие, имеют тип возвращаемого значения, объявленный как void. В отличие от C++, методы в Java не могут иметь значения аргументов по умолчанию , и вместо этого методы обычно перегружаются.

class Foo {
    int bar(int a, int b) {
        return (a*2) + b;
    }

    /* Overloaded method with the same name but different set of arguments */
    int bar(int a) {
        return a*2;
    }
}

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

Foo foo = new Foo();
int result = foo.bar(7, 2); // Non-static method is called on foo

int finalResult = Math.abs(result); // Static method call

The throws Ключевое слово указывает, что метод генерирует исключение. Все отмеченные исключения должны быть перечислены в виде списка, разделенного запятыми.

void openStream() throws IOException, myException { // Indicates that IOException may be thrown
}
Модификаторы
[ редактировать ]
  • abstract Абстрактные методы могут присутствовать только в абстрактных классах , такие методы не имеют тела и должны быть переопределены в подклассе, если он сам не является абстрактным.
  • static — Делает метод статическим и доступным без создания экземпляра класса. Однако статические методы не могут получить доступ к нестатическим членам того же класса.
  • final — Объявляет, что метод не может быть переопределен в подклассе.
  • native — Указывает, что этот метод реализован через JNI в платформо-зависимом коде. Фактическая реализация происходит вне кода Java, и такие методы не имеют тела.
  • strictfp - Декларирует строгое соответствие стандарту IEEE 754 при выполнении операций с плавающей запятой.
  • synchronized — Объявляет, что поток, выполняющий этот метод, должен получить монитор. Для synchronized методы, монитор является экземпляром класса или java.lang.Class если метод статический.
  • Модификаторы доступа — идентичны тем, которые используются с классами.
Заключительные методы
[ редактировать ]

Последний метод не может быть переопределен или скрыт подклассами. [ 5 ] Это используется для предотвращения неожиданного поведения подкласса, изменяющего метод, который может иметь решающее значение для функции или согласованности класса. [ 6 ]

Пример:

public class Base
{
    public       void m1() {...}
    public final void m2() {...}

    public static       void m3() {...}
    public static final void m4() {...}
}

public class Derived extends Base
{
    public void m1() {...}  // OK, overriding Base#m1()
    public void m2() {...}  // forbidden

    public static void m3() {...}  // OK, hiding Base#m3()
    public static void m4() {...}  // forbidden
}

Распространенным заблуждением является то, что объявление метода как final повышает эффективность, позволяя компилятору напрямую вставлять метод везде, где он вызывается (см. встроенное расширение ). Поскольку метод загружается во время выполнения , компиляторы не могут этого сделать. Только среда выполнения и JIT- компилятор точно знают, какие классы были загружены, и поэтому только они могут принимать решения о том, когда встраивать, является ли метод окончательным или нет. [ 7 ]

, специфичный для платформы компиляторы машинного кода, которые генерируют непосредственно исполняемый машинный код Исключением являются . При использовании статического связывания компилятор может с уверенностью предположить, что методы и переменные, вычисляемые во время компиляции, могут быть встроены.

Эта языковая функция была представлена ​​в J2SE 5.0 . Последний аргумент метода может быть объявлен как параметр переменной арности, и в этом случае метод становится методом переменной арности (в отличие от методов с фиксированной арностью) или просто varargs методом . Это позволяет передавать в метод в качестве параметров переменное количество значений объявленного типа, включая отсутствие параметров. Эти значения будут доступны внутри метода в виде массива.

void printReport(String header, int... numbers) { //numbers represents varargs
    System.out.println(header);
    for (int num : numbers) {
        System.out.println(num);
    }
}

// Calling varargs method
printReport("Report data", 74, 83, 25, 96);

Поля или переменные класса могут быть объявлены внутри тела класса для хранения данных.

class Foo {
    double bar;
}

Поля могут быть инициализированы непосредственно при объявлении.

class Foo {
    double bar = 2.3;
}
Модификаторы
[ редактировать ]
  • static - Делает поле статическим элементом.
  • final — Позволяет инициализировать поле только один раз в конструкторе, внутри блока инициализации или во время его объявления, в зависимости от того, что наступит раньше.
  • transient — Указывает, что это поле не будет сохранено во время сериализации .
  • volatile - Если поле объявлено volatile, гарантируется, что все потоки видят единое значение переменной.

Наследование

[ редактировать ]

Классы в Java могут наследовать только от одного класса. Класс может быть производным от любого класса, который не помечен как final. Наследование объявляется с помощью extends ключевое слово. Класс может ссылаться на себя, используя this ключевое слово и его прямой суперкласс с использованием super ключевое слово.

class Foo {

}

class Foobar extends Foo {

}

Если класс не указывает свой суперкласс, он неявно наследуется от java.lang.Object сорт. Таким образом, все классы в Java являются подклассами Object сорт.

Если у суперкласса нет конструктора без параметров, подкласс должен указать в своих конструкторах, какой конструктор суперкласса использовать. Например:

class Foo {
    public Foo(int n) {
        // Do something with n
    }
}

class Foobar extends Foo {
    private int number;
    // Superclass does not have constructor without parameters
    // so we have to specify what constructor of our superclass to use and how

    public Foobar(int number) {
        super(number);
        this.number = number;
    }
}
Переопределение методов
[ редактировать ]

В отличие от C++, все не- final методы в Java являются виртуальными и могут быть переопределены наследующими классами.

class Operation {
    public int doSomething() {
        return 0;
    }
}

class NewOperation extends Operation {
    @Override
    public int doSomething() {
        return 1;
    }
}
Абстрактные классы
[ редактировать ]

Абстрактный класс — это класс, который является неполным или должен считаться неполным, поэтому не может быть создан экземпляр.

Класс C имеет абстрактные методы, если выполняется любое из следующих условий:

  • C явно содержит объявление абстрактного метода.
  • Любой из суперклассов C имеет абстрактный метод, и C не объявляет и не наследует метод, который его реализует.
  • Прямой суперинтерфейс C объявляет или наследует метод (который, следовательно, обязательно является абстрактным), а C не объявляет и не наследует метод, который его реализует.
  • Можно создать экземпляр подкласса абстрактного класса, который сам по себе не является абстрактным, что приведет к выполнению конструктора абстрактного класса и, следовательно, к выполнению инициализаторов полей для переменных экземпляра этого класса.
package org.dwwwp.test;

/**
 * @author jcrypto
 */
public class AbstractClass {
    private static final String hello;

    static {
        System.out.println(AbstractClass.class.getName() + ": static block runtime");
        hello = "hello from " + AbstractClass.class.getName();
    }

    {
        System.out.println(AbstractClass.class.getName() + ": instance block runtime");
    }

    public AbstractClass() {
        System.out.println(AbstractClass.class.getName() + ": constructor runtime");
    }

    public static void hello() {
        System.out.println(hello);
    }
}
package org.dwwwp.test;

/**
 * @author jcrypto
 */
public class CustomClass extends AbstractClass {

    static {
        System.out.println(CustomClass.class.getName() + ": static block runtime");
    }

    {
        System.out.println(CustomClass.class.getName() + ": instance block runtime");
    }

    public CustomClass() {
        System.out.println(CustomClass.class.getName() + ": constructor runtime");
    }

    public static void main(String[] args) {
        CustomClass nc = new CustomClass();
        hello();
        //AbstractClass.hello();//also valid
    }
}

Выход:

org.dwwwp.test.AbstractClass: static block runtime
org.dwwwp.test.CustomClass: static block runtime
org.dwwwp.test.AbstractClass: instance block runtime
org.dwwwp.test.AbstractClass: constructor runtime
org.dwwwp.test.CustomClass: instance block runtime
org.dwwwp.test.CustomClass: constructor runtime
hello from org.dwwwp.test.AbstractClass

Перечисления

[ редактировать ]

Эта языковая функция была представлена ​​в J2SE 5.0 . Технически перечисления — это своего рода класс, содержащий константы перечисления в своем теле. Каждая константа перечисления определяет экземпляр типа перечисления. Классы перечисления не могут быть созданы нигде, кроме как в самом классе перечисления.

enum Season {
    WINTER, SPRING, SUMMER, AUTUMN
}

Константы перечисления могут иметь конструкторы, которые вызываются при загрузке класса:

public enum Season {
    WINTER("Cold"), SPRING("Warmer"), SUMMER("Hot"), AUTUMN("Cooler");

    Season(String description) {
        this.description = description;
    }

    private final String description;

    public String getDescription() {
        return description;
    }
}

Перечисления могут иметь тела классов, и в этом случае они рассматриваются как анонимные классы, расширяющие класс перечисления:

public enum Season {
    WINTER {
        String getDescription() {return "cold";}
    },
    SPRING {
        String getDescription() {return "warmer";}
    },
    SUMMER {
        String getDescription() {return "hot";}
    },
    FALL {
        String getDescription() {return "cooler";}
    };
}

Интерфейсы

[ редактировать ]

Интерфейсы — это типы, которые не содержат полей и обычно определяют ряд методов без фактической реализации. Они полезны для определения контракта с любым количеством различных реализаций. Каждый интерфейс неявно абстрактен. Методам интерфейса разрешено иметь подмножество модификаторов доступа в зависимости от версии языка. strictfp, что имеет тот же эффект, что и для классов, а также static начиная с Java SE 8.

interface ActionListener {
    int ACTION_ADD = 0;
    int ACTION_REMOVE = 1;
 
    void actionSelected(int action);
}

Реализация интерфейса

[ редактировать ]

Интерфейс реализуется классом с использованием implements ключевое слово. Допускается реализация более одного интерфейса, в этом случае они пишутся после implements ключевое слово в списке, разделенном запятыми. Класс, реализующий интерфейс, должен переопределить все его методы, в противном случае его необходимо объявить как абстрактный.

interface RequestListener {
    int requestReceived();
}

class ActionHandler implements ActionListener, RequestListener {
    public void actionSelected(int action) {
    }

    public int requestReceived() {
    }
}

//Calling method defined by interface
RequestListener listener = new ActionHandler(); /*ActionHandler can be
                                   represented as RequestListener...*/
listener.requestReceived(); /*...and thus is known to implement
                            requestReceived() method*/

Функциональные интерфейсы и лямбда-выражения

[ редактировать ]

Эти функции были представлены с выпуском Java SE 8. Интерфейс автоматически становится функциональным интерфейсом, если он определяет только один метод. В этом случае реализацию можно представить в виде лямбда-выражения вместо реализации ее в новом классе, что значительно упрощает написание кода в функциональном стиле . Функциональные интерфейсы могут быть дополнительно аннотированы с помощью @FunctionalInterface аннотация, которая сообщит компилятору проверить, действительно ли интерфейс соответствует определению функционального интерфейса.

// A functional interface
@FunctionalInterface
interface Calculation {
    int calculate(int someNumber, int someOtherNumber);
}

// A method which accepts this interface as a parameter
int runCalculation(Calculation calculation) {
    return calculation.calculate(1, 2);
}

// Using a lambda to call the method
runCalculation((number, otherNumber) -> number + otherNumber);

// Equivalent code which uses an anonymous class instead
runCalculation(new Calculation() {
    @Override
    public int calculate(int someNumber, int someOtherNumber) {
        return someNumber + someOtherNumber;
    }
})

Типы параметров Lambda не требуют полного указания и могут быть выведены из реализуемого им интерфейса. Тело Lambda можно записать без блока body и return утверждение, если это всего лишь выражение. Кроме того, для тех интерфейсов, метод которых имеет только один параметр, круглые скобки можно опустить. [ 8 ]

// Same call as above, but with fully specified types and a body block
runCalculation((int number, int otherNumber) -> {
    return number + otherNumber;
});

// A functional interface with a method which has only a single parameter
interface StringExtender {
    String extendString(String input);
}

// Initializing a variable of this type by using a lambda
StringExtender extender = input -> input + " Extended";

Ссылки на методы

[ редактировать ]

Нет необходимости использовать лямбды, если уже существует именованный метод, совместимый с интерфейсом. Этот метод можно передать вместо лямбды, используя ссылку на метод. Существует несколько типов ссылок на методы:

Тип ссылки Пример Эквивалентная лямбда
Статический Integer::sum (number, otherNumber) -> number + otherNumber
Граница "LongString"::substring index -> "LongString".substring(index)
Несвязанный String::isEmpty string -> string.isEmpty()
Конструктор класса ArrayList<String>::new capacity -> new ArrayList<String>(capacity)
Конструктор массива String[]::new size -> new String[size]

Код выше, который вызывает runCalculation можно заменить следующим, используя ссылки на методы:

runCalculation(Integer::sum);

Наследование

[ редактировать ]

Интерфейсы могут наследовать от других интерфейсов, как и классы. В отличие от классов разрешено наследование от нескольких интерфейсов. Однако возможно, что несколько интерфейсов имеют поле с одинаковым именем, и в этом случае оно становится одним неоднозначным элементом, к которому невозможно получить доступ.

/* Class implementing this interface must implement methods of both
ActionListener and RequestListener */
interface EventListener extends ActionListener, RequestListener {    
}

Методы по умолчанию

[ редактировать ]

В Java SE 8 в интерфейсы добавлены методы по умолчанию, что позволяет разработчикам добавлять новые методы к существующим интерфейсам, не нарушая совместимости с классами, уже реализующими интерфейс. В отличие от обычных методов интерфейса, методы по умолчанию имеют тело, которое будет вызвано в том случае, если реализующий класс не переопределит его.

interface StringManipulator {
    String extendString(String input);
    
    // A method which is optional to implement
    default String shortenString(String input) {
        return input.substring(1);
    }
}

// This is a valid class despite not implementing all the methods
class PartialStringManipulator implements StringManipulator {
    @Override
    public String extendString(String input) {
        return input + " Extended";
    }
}

Статические методы

[ редактировать ]

Статические методы — это еще одна особенность языка, представленная в Java SE 8. Они ведут себя точно так же, как и классы.

interface StringUtils {
    static String shortenByOneSymbol(String input) {
        return input.substring(1);
    }
}

StringUtils.shortenByOneSymbol("Test");

Частные методы

[ редактировать ]

Частные методы были добавлены в выпуске Java 9. Интерфейс может иметь метод с телом, помеченным как частный, и в этом случае он не будет виден наследующим классам. Его можно вызывать из методов по умолчанию для повторного использования кода.

interface Logger {
    default void logError() {
        log(Level.ERROR);
    }

    default void logInfo() {
        log(Level.INFO);
    }

    private void log(Level level) {
        SystemLogger.log(level.id);
    }
}

Аннотации

[ редактировать ]

Аннотации в Java — это способ встраивания метаданных в код. Эта языковая функция была представлена ​​в J2SE 5.0 .

Типы аннотаций
[ редактировать ]

В Java имеется набор предопределенных типов аннотаций, но разрешено определять новые. Объявление типа аннотации — это особый тип объявления интерфейса. Они объявляются так же, как и интерфейсы, за исключением interface Ключевому слову предшествует @ знак. Все аннотации неявно расширяются из java.lang.annotation.Annotation и не может быть продолжено ни от чего другого.

@interface BlockingOperations {
}

Аннотации могут иметь те же объявления в теле, что и общие интерфейсы, кроме того, им разрешено включать перечисления и аннотации. Основное отличие состоит в том, что объявления абстрактных методов не должны иметь никаких параметров или вызывать какие-либо исключения. Также они могут иметь значение по умолчанию, которое объявляется с помощью default ключевое слово после имени метода:

@interface BlockingOperations {
    boolean fileSystemOperations();
    boolean networkOperations() default false;
}
Использование аннотаций
[ редактировать ]

Аннотации могут использоваться в любом виде объявления, будь то пакет, класс (включая перечисления), интерфейс (включая аннотации), поле, метод, параметр, конструктор или локальная переменная. Также их можно использовать с константами перечисления. Аннотации объявляются с использованием @ знак, предшествующий имени типа аннотации, после которого в скобках записываются пары элемент-значение. Всем элементам без значения по умолчанию должно быть присвоено значение.

@BlockingOperations(/*mandatory*/ fileSystemOperations,
/*optional*/ networkOperations = true)
void openOutputStream() { //Annotated method
}

Помимо общей формы, существуют две другие формы объявления аннотации, которые являются сокращениями. Маркерная аннотация — это краткая форма, она используется, когда элементам не присвоены значения:

@Unused // Shorthand for @Unused()
void travelToJupiter() {
}

Другая короткая форма называется аннотацией одного элемента . Он используется с типами аннотаций, содержащими только один элемент, или в случае, когда присутствует несколько элементов, но только у одного элемента отсутствует значение по умолчанию. В форме аннотации одного элемента имя элемента опускается и вместо него записывается только значение:

/* Equivalent for @BlockingOperations(fileSystemOperations = true).
networkOperations has a default value and
does not have to be assigned a value */

@BlockingOperations(true)
void openOutputStream() {
}

Дженерики

[ редактировать ]

Обобщения , или параметризованные типы, или параметрический полиморфизм — одна из основных функций, представленных в J2SE 5.0 . До того, как были введены дженерики, требовалось явно объявлять все типы. С помощью дженериков стало возможным работать аналогичным образом с разными типами без объявления точных типов. Основная цель дженериков — обеспечить безопасность типов и обнаружить ошибки времени выполнения во время компиляции. В отличие от C#, информация об используемых параметрах недоступна во время выполнения из-за стирания типа . [ 9 ]

Общие классы

[ редактировать ]

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

Можно ограничить переменную типа подтипом определенного класса или объявить интерфейс, который должен быть реализован этим типом. В этом случае к переменной типа добавляется extends ключевое слово, за которым следует имя класса или интерфейса. Если переменная ограничена как классом, так и интерфейсом или имеется несколько интерфейсов, сначала записывается имя класса, а затем имена интерфейсов с & знак, используемый в качестве разделителя.

/* This class has two type variables, T and V. T must be 
a subtype of ArrayList and implement Formattable interface */
public class Mapper<T extends ArrayList & Formattable, V> {
    public void add(T array, V item) {
        // array has add method because it is an ArrayList subclass
        array.add(item);
    }
}

Когда объявляется переменная параметризованного типа или создается экземпляр, ее тип записывается точно в том же формате, что и в заголовке класса, за исключением того, что фактический тип записывается вместо объявления переменной типа.

/* Mapper is created with CustomList as T and Integer as V.
CustomList must be a subclass of ArrayList and implement Formattable */
Mapper<CustomList, Integer> mapper = new Mapper<CustomList, Integer>();

Начиная с Java SE 7, можно использовать ромб ( <>) вместо аргументов типа, и в этом случае будут выведены последние. Следующий код в Java SE 7 эквивалентен коду в предыдущем примере:

Mapper<CustomList, Integer> mapper = new Mapper<>();

При объявлении переменной для параметризованного типа можно использовать подстановочные знаки вместо явных имен типов. Подстановочные знаки выражаются написанием ? знак вместо фактического типа. Можно ограничить возможные типы подклассами или суперклассами некоторого конкретного класса, написав extends ключевое слово или super ключевое слово, за которым следует имя класса.

/* Any Mapper instance with CustomList as the first parameter
may be used regardless of the second one.*/
Mapper<CustomList, ?> mapper;
mapper = new Mapper<CustomList, Boolean>();
mapper = new Mapper<CustomList, Integer>();

/* Will not accept types that use anything but
a subclass of Number as the second parameter */
void addMapper(Mapper<?, ? extends Number> mapper) {
}

Универсальные методы и конструкторы

[ редактировать ]

Использование дженериков может быть ограничено некоторыми конкретными методами; эта концепция применима и к конструкторам. Чтобы объявить параметризованный метод, переменные типа записываются перед возвращаемым типом метода в том же формате, что и для универсальных классов. В случае конструктора переменные типа объявляются перед именем конструктора.

class Mapper {
    // The class itself is not generic, the constructor is
    <T, V> Mapper(T array, V item) {
    }
}

/* This method will accept only arrays of the same type as
the searched item type or its subtype*/
static <T, V extends T> boolean contains(T item, V[] arr) {
    for (T currentItem : arr) {
        if (item.equals(currentItem)) {
            return true;
        }
    }
    return false;
}

Общие интерфейсы

[ редактировать ]

Интерфейсы можно параметризовать аналогично классам.

interface Expandable<T extends Number> {
    void addItem(T item);
}

// This class is parameterized
class Array<T extends Number> implements Expandable<T> {
    void addItem(T item) {
    }
}

// And this is not and uses an explicit type instead
class IntegerArray implements Expandable<Integer> {
    void addItem(Integer item) {
    }
}

См. также

[ редактировать ]
  1. ^ «Операторы (Учебные пособия по Java™ > Изучение языка Java > Основы языка)» . docs.oracle.com . Oracle и/или ее дочерние компании . Проверено 16 июня 2015 г.
  2. ^ «Оператор switch (Учебные пособия по Java™ > Изучение языка Java > Основы языка)» . docs.oracle.com . Проверено 15 августа 2021 г.
  3. ^ Оуэнс, Шон. «Java и unsigned int, unsigned short, unsigned byte, unsigned long и т.д. (вернее, их отсутствие)» .
  4. ^ «Примитивные типы данных» .
  5. ^ «Глава 8. Занятия» . docs.oracle.com . Проверено 25 апреля 2024 г.
  6. ^ «Написание финальных классов и методов» . docs.oracle.com . Проверено 25 апреля 2024 г.
  7. ^ «Теория и практика Java: это ваш окончательный ответ?» . разработчик.ibm.com . Архивировано из оригинала 8 февраля 2009 г. Проверено 25 апреля 2024 г.
  8. ^ «Лямбда-выражения (Учебные пособия по Java™ > Изучение языка Java > Классы и объекты)» . docs.oracle.com . Проверено 8 августа 2021 г.
  9. ^ Обобщенные шаблоны во время выполнения (Руководство по программированию на C#)
[ редактировать ]
Arc.Ask3.Ru: конец переведенного документа.
Arc.Ask3.Ru
Номер скриншота №: eaae01a863b03471bd438c0994e7f23f__1720892280
URL1:https://arc.ask3.ru/arc/aa/ea/3f/eaae01a863b03471bd438c0994e7f23f.html
Заголовок, (Title) документа по адресу, URL1:
Java syntax - Wikipedia
Данный printscreen веб страницы (снимок веб страницы, скриншот веб страницы), визуально-программная копия документа расположенного по адресу URL1 и сохраненная в файл, имеет: квалифицированную, усовершенствованную (подтверждены: метки времени, валидность сертификата), открепленную ЭЦП (приложена к данному файлу), что может быть использовано для подтверждения содержания и факта существования документа в этот момент времени. Права на данный скриншот принадлежат администрации Ask3.ru, использование в качестве доказательства только с письменного разрешения правообладателя скриншота. Администрация Ask3.ru не несет ответственности за информацию размещенную на данном скриншоте. Права на прочие зарегистрированные элементы любого права, изображенные на снимках принадлежат их владельцам. Качество перевода предоставляется как есть. Любые претензии, иски не могут быть предъявлены. Если вы не согласны с любым пунктом перечисленным выше, вы не можете использовать данный сайт и информация размещенную на нем (сайте/странице), немедленно покиньте данный сайт. В случае нарушения любого пункта перечисленного выше, штраф 55! (Пятьдесят пять факториал, Денежную единицу (имеющую самостоятельную стоимость) можете выбрать самостоятельно, выплаичвается товарами в течение 7 дней с момента нарушения.)