Spec-Zone .ru
спецификации, руководства, описания, API
Содержание | Предыдущий | Следующий | ИндексСпецификация Виртуальной машины JavaTM


ГЛАВА 2

Понятия Java


Виртуальная машина Java была разработана, чтобы поддерживать язык программирования Java. Некоторые понятия и словарь с языка Java таким образом необходимы, чтобы понять виртуальную машину. Эта глава дает действительно краткий обзор Java, чтобы поддерживать обсуждение виртуальной машины Java, чтобы следовать. Его материал был сжат из Спецификации языка Java, Джеймсом Гослингом, Биллом Джоем, и Гаем Стилом. Для полного обсуждения языка Java, или для деталей и примеров материала в этой главе, ссылаются на ту книгу. Читатели, знакомые с той книгой, могут хотеть пропустить эту главу. Читатели, знакомые с Java, но не со Спецификацией языка Java, должны, по крайней мере, просмотреть эту главу для терминологии, которую это представляет.

Эта глава не пытается обеспечить введение в или полную обработку языка Java. Для введения в Java см. Язык программирования Java Кеном Арнольдом и Джеймсом Гослингом.


2.1 Unicode

Программы Java пишутся, используя кодировку символов Unicode, версию 1.1.5, как определено в Стандарте Unicode: Глобальная Кодировка символов, Версия 1.0, Объем 1, ISBN 0-201-56788-1, и Объем 2, ISBN 0-201-60845-6, и информация об обновлении о Unicode 1.1.5 доступный в ftp://unicode.org. В этой информации об обновлении есть несколько незначительных ошибок; сошлитесь на Спецификацию языка Java для исправлений. Обновления к информации о Unicode, опубликованной там, будут отправлены под URL http://java.sun.com/docs/books/index.html.

За исключением комментариев и идентификаторов (§2.2) и содержание символьных и строковых литералов (§2.3), все входные элементы в программе Java формируются из только символов ASCII. ASCII (ANSI X3.4) является Стандартный американский код обмена информацией. Первые 128 символов кодировки символов Unicode являются символами ASCII.


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

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

Метод Java Character.isJavaLetter возвраты true когда передано символ Unicode, который, как полагают, является буквой в идентификаторах Java. Метод Java Character.isJavaLetterOrDigit возвраты true когда передано символ Unicode, который, как полагают, является буквой или цифрой в идентификаторах Java.

Два идентификатора являются тем же самым, только если у них есть тот же самый символ Unicode для каждой буквы или цифры; идентификаторы, у которых есть то же самое внешнее появление, могут все еще отличаться. Идентификатор не должен быть тем же самым как ключевым словом Java или булевым литералом (true or false).


2.3 Литералы

Литерал является представлением исходного кода значения типа примитива (§2.4.1), String введите (§2.4.7), или нулевой тип (§2.4). Строковые литералы и, более широко, строки, которые являются значениями константных выражений, "интернируются", чтобы совместно использовать уникальные экземпляры, используя метод String.intern.

У нулевого типа есть одно значение, нулевая ссылка, обозначенная литералом null.

boolean у типа есть два значения, обозначенные литералами true и false.


2.4 Типы и Значения

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

Типы языка Java делятся на две категории: типы примитивов (§2.4.1) и ссылочные типы (§2.4.5). Есть также специальный нулевой тип, тип выражения null, у которого нет никакого имени. Нулевая ссылка является единственным возможным значением выражения нулевого типа, и может всегда преобразовываться в любой ссылочный тип. Практически, программист Java может проигнорировать нулевой тип и только симулировать это null специальный литерал, который может иметь любой ссылочный тип.

Соответствуя типам примитивов и ссылочным типам, есть две категории значений данных, которые могут быть сохранены в переменных, передали как параметры, возвращенные методами, и работали на: примитивные значения (§2.4.1) и ссылочные значения (§2.4.5).

2.4.1 Типы примитивов и Значения

Тип примитива является типом, который предопределяется языком Java и называется зарезервированным словом. Примитивные значения не совместно используют состояние с другими примитивными значениями. Переменная, тип которой является типом примитива всегда, содержит примитивное значение того типа 1

Типы примитивов boolean введите и числовые типы. Числовые типы являются целочисленными типами и типами с плавающей точкой.

Целочисленные типы byte, short, int, и long, чьи значения являются 8-разрядными, 16-разрядными, 32-разрядными, и 64-разрядными two's-дополнительными целыми числами со знаком, соответственно, и char, чьи значения являются 16-разрядными целыми без знака, представляющими символы Unicode (§2.1).

Типы с плавающей точкой float, чьи значения являются 32-разрядным IEEE 754 числа с плавающей точкой, и double, чьи значения являются 64-разрядным IEEE 754 числа с плавающей точкой как определено в Стандарте IEEE для Двоичной Арифметики С плавающей точкой, Стандарт ANSI/IEEE 754-1985 (IEEE, Нью-Йорк). Стандарт IEEE 754 включает не только положительный и числа величины знака минус, но также и положительный, и отрицательный обнуляет, положительные и отрицательные бесконечности, и специальное Не-число (после этого сокращал НЭН), значение. Значение НЭН используется, чтобы представить результат определенных операций, таких как делящийся нуль нулем.

boolean у типа есть значения истинности true и false.

2.4.2 Операторы на Интегральных Значениях

Java предоставляет многим операторам, которые действуют на интегральные значения, включая числовое сравнение (который приводит к значению типа boolean), арифметические операторы, постепенно увеличьтесь и декрементный, поразрядный логичный и операторы сдвига, и числовой бросок (§2.6.8).

Операнды определенных унарных операторов и бинарных операторов подвергаются числовому продвижению (§2.6.9).

Встроенные целочисленные операторы не указывают на переполнение или потерю значимости всегда; они повторяются на переполнении или потере значимости. Единственные целочисленные операторы, которые могут выдать исключение, являются целочисленным дележом и целочисленными операторами остатка, которые могут бросить ArithmeticException если правый операнд является нулем.

Любое значение любого целочисленного типа может быть брошено к или от любого числового типа. Нет никаких бросков между целочисленными типами и типом boolean.

2.4.3 Операторы на Значениях С плавающей точкой

Java предоставляет многим операторам, которые действуют на значения с плавающей точкой, включая числовое сравнение (который приводит к значению типа boolean), арифметические операторы, инкремент и декремент, и числовой бросок (§2.6.8).

Если по крайней мере один из операндов к бинарному оператору имеет тип с плавающей точкой, то работа является работой с плавающей точкой, даже если другой операнд является неотъемлемой частью. Операнды определенных унарных операторов и бинарных операторов подвергаются числовому продвижению (§2.6.9).

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

Java требует, чтобы арифметика с плавающей точкой вела себя как будто каждый оператор с плавающей точкой, округленный ее результат с плавающей точкой к точности результата. Неточные результаты должны быть округлены к представимому значению, самому близкому к бесконечно точному результату; если два самых близких представимых значения одинаково рядом, тот с его младшим значащим разрядным нулем выбирается. Это - значение по умолчанию стандарта IEEE 754 округление режима, известного как раунд-к-самому-близкому.

Java использует режим раунда к нулю, преобразовывая значение с плавающей точкой в целое число (§2.6.3). Режим раунда к нулю действует, как если бы число было усеченным, отбрасывая биты мантиссы. Раунд к нулю выбирает как его результат значение формата, самое близкое к и не больше в величине чем бесконечно точный результат.

Java операторы с плавающей точкой не производит исключений (§2.15). Работа, которая переполнения производят бесконечность со знаком; работа, которая потери значимости производят нуль со знаком; и работа, у которой нет никакого математически определенного результата, производит НЭН. Все числовые операции (за исключением числового сравнения) с НЭН как операнд производит НЭН в результате.

Любое значение любого типа с плавающей точкой может быть брошено (§2.6.8) к или от любого числового типа. Нет никаких бросков между типами с плавающей точкой и типом boolean.

2.4.4 Операторы на boolean Значения

Булевы операторы включают операторы отношения и логические операторы. Только boolean выражения могут использоваться в операторах управления Java и как первый операнд условного оператора ?:. Интегральное значение x может быть преобразован в значение типа boolean, после соглашения языка C, которое любое ненулевое значение true, по выражению x!=0. Ссылка на объект obj может быть преобразован в значение типа boolean, после соглашения языка C, что любая ссылка кроме null true, по выражению obj!=null.

Между типом нет никаких бросков boolean и любой другой тип.

2.4.5 Ссылочные типы, Объекты, и Ссылочные Значения

Есть три вида ссылочных типов: типы классов (§2.8), интерфейсные типы (§2.13), и типы массива (§2.14). Объект является динамически создаваемым экземпляром класса или массивом. Ссылочные значения (часто только ссылки) являются указателями на эти объекты и специальную нулевую ссылку, которая не обращается ни к какому объекту.

Экземпляр класса явно создается выражением создания экземпляра класса, или вызывая newInstance метод класса Class. Массив явно создается выражением создания массива. Объект создается в "куче" Java, и собирается "мусор" после того, как нет больше ссылок на это. Объекты никогда не исправляются или освобождаются явными директивами языка Java.

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

У каждого объекта есть связанная блокировка (§2.17, §8.13), который используется synchronized методы и synchronized оператор, чтобы обеспечить управление параллельным доступом, чтобы утвердить многократными потоками (§2.17, §8.12).

Ссылочные типы формируют иерархию. Каждый тип класса является подклассом другого типа класса, за исключением класса Object (§2.4.6), который является суперклассом (§2.8.3) всех других типов классов. Все объекты, включая массивы, поддерживают методы класса Object. Строковые литералы (§2.3) являются ссылками на экземпляры класса String (§2.4.7).

2.4.6 Класс Object

Стандартный класс Object суперкласс (§2.8.3) всех других классов. Переменная типа Object может содержать ссылку на любой объект, является ли это экземпляром класса или массива. Весь класс и типы массива наследовали методы класса Object.

2.4.7 Класс String

Экземпляры класса String представьте последовательности символов Unicode (§2.1). A String у объекта есть постоянное, неизменное значение. Строковые литералы (§2.3) являются ссылками на экземпляры класса String.

2.4.8 Операторы на Объектах

Операторы на объектах включают доступ к полю, вызов метода, бросок, конкатенацию строк, сравнение для равенства, instanceof, и условный оператор ?:.


2.5 Переменные

Переменная является местом хранения. У этого есть связанный тип, иногда называемый его типом времени компиляции, который является или типом примитива (§2.4.1) или ссылочным типом (§2.4.5). Переменная всегда содержит значение, которое является присвоением, совместимым (§2.6.6) с его типом. Переменная типа примитива всегда содержит значение того точного типа примитива. Переменная ссылочного типа может содержать или нулевую ссылку или ссылку на любой объект, класс которого является присвоением, совместимым (§2.6.6) с типом переменной.

Совместимость значения переменной с ее типом гарантируется проектом языка Java, потому что значения по умолчанию (§2.5.1) являются совместимыми, и все присвоения на переменную проверяются, во время компиляции, для совместимости присвоения.

Есть семь видов переменных:

  1. Переменная класса является полем типа класса, объявленного, используя ключевое слово static (§2.9.1) в пределах объявления класса, или с или без ключевого слова static в интерфейсном объявлении. Переменные класса создаются, когда класс или интерфейс загружаются (§2.16.2) и инициализируются на создании к значениям по умолчанию (§2.5.1). Переменная класса эффективно прекращает существование, когда ее класс или интерфейс разгружаются (§2.16.8) после того, как любое необходимое завершение класса (§2.16.8) было завершено.
  2. Переменная экземпляра является полем, объявленным в пределах объявления класса, не используя ключевое слово static (§2.9.1). Если у класса T есть поле a, которое является переменной экземпляра, то новая переменная экземпляра создаваемого и инициализированного к значению по умолчанию (§2.5.1) как часть каждого недавно создаваемого объекта класса T или любого класса, который является подклассом T. Переменная экземпляра эффективно прекращает существование, когда, объектом которого это - поле, больше не ссылается, после любого необходимого завершения объекта был завершен (§2.16.7).
  3. Компоненты массива являются неназванными переменными, которые создаются и инициализируются к значениям по умолчанию (§2.5.1) всякий раз, когда новый объект, который является массивом, создается (§2.16.6). Компоненты массива эффективно прекращают существование, когда на массив больше не ссылаются.
  4. Параметры метода называют значения аргументов переданными к методу. Для каждого параметра, объявленного в объявлении метода, новая переменная параметра создается каждый раз, когда метод вызывается. Новая переменная инициализируется с соответствующим значением аргумента от вызова метода. Параметр метода эффективно прекращает существование, когда выполнение тела метода полно.
  5. Параметры конструктора называют значения аргументов переданными конструктору. Для каждого параметра, объявленного в объявлении конструктора, новая переменная параметра создается каждый раз, когда выражение создания экземпляра класса или явный вызов конструктора оцениваются. Новая переменная инициализируется с соответствующим значением аргумента от выражения создания или вызова конструктора. Параметр конструктора эффективно прекращает существование, когда выполнение тела конструктора полно.
  6. Переменная параметра обработчика исключений создается каждый раз, когда исключение поймано a catch пункт a try оператор (§2.15.2). Новая переменная инициализируется с фактическим объектом, связанным с исключением (§2.15.3). Параметр обработчика исключений эффективно прекращает существование когда выполнение блока, связанного с catch пункт (§2.15.2) полон.
  7. Локальные переменные объявляются операторами объявления локальной переменной. Всякий раз, когда поток управления вводит блок или a for оператор, новая переменная создается для каждой локальной переменной, объявленной в операторе объявления локальной переменной, сразу содержавшем в пределах того блока или for оператор. Локальная переменная не инициализируется, однако, до оператора объявления локальной переменной, который объявляет, что это выполняется. Локальная переменная эффективно прекращает существование когда выполнение блока или for оператор полон.

2.5.1 Начальные значения Переменных

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

2.5.2 У переменных Есть Типы, у Объектов Есть Классы

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

(Иногда у переменной или выражения, как говорят, есть "тип времени выполнения," но это - злоупотребление терминологией; это обращается к классу объекта, упомянутого значением переменной или выражения во время выполнения, предполагая, что значение не null. Должным образом разговор, тип является понятием времени компиляции. У переменной или выражения есть тип; объект или массив не имеют никакого типа, но принадлежат классу.)

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

Даже при том, что у переменной или выражения может быть тип времени компиляции, который является интерфейсным типом, нет никаких экземпляров интерфейсов (§2.13). Переменная или выражение, тип которого является интерфейсным типом, могут сослаться на любой объект чьи реализации класса тот интерфейс.

У каждого массива также есть класс. У классов для массивов есть странные имена, которые не являются допустимыми идентификаторами Java; например, класс для массива int у компонентов есть имя "[I".


2.6 Преобразования и Продвижения

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

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

В Java есть шесть широких видов преобразований:

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

Преобразование строк только применяется к операндам двоичного файла + оператор, когда одним из параметров является a String; это не будет покрыто далее.

2.6.1 Преобразования идентификационных данных

Преобразование от типа до того же самого типа разрешается для любого типа.

2.6.2 Расширение Примитивных Преобразований

Следующие преобразования на типах примитивов вызывают расширяющимися примитивными преобразованиями:

Расширяющиеся преобразования не теряют информацию о знаке или порядке величины числового значения. Преобразования, расширяющиеся от целочисленного типа до другого целочисленного типа и от float к double не теряйте информацию вообще; числовое значение сохраняется точно. Преобразование int или a long значение к float, или a long значение к double, может потерять точность, то есть, результат может потерять некоторые из младших значащих битов значения; получающееся значение с плавающей точкой является правильно округленной версией целочисленного значения, используя режим раунда-к-самому-близкому IEEE 754 (§2.4.3).

Согласно этому правилу, расширяющееся преобразование целого числа со знаком оценивает целочисленному типу, просто подписываются - расширяет two's-дополнительное представление целочисленного значения, чтобы заполнить более широкий формат. Расширяющееся преобразование значения типа char к нулю целочисленного типа - расширяет представление символьного значения, чтобы заполнить более широкий формат.

Несмотря на то, что потеря точности может произойти, расширяя преобразования среди типов примитивов никогда не приводит к исключению на этапе выполнения (§2.15).

2.6.3 Сужение Примитивных Преобразований

Следующие преобразования на типах примитивов вызывают, сужая примитивные преобразования:

Сужение преобразований может потерять информацию о знаке или порядке величины, или обоих, числового значения (например, сужаясь int значение 32763 вводить byte производит значение -5). Сужение преобразований может также потерять точность.

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

Сужающееся преобразование символа к целочисленному типу аналогично просто отбрасывает все кроме n самых низких битов, где n является числом битов, используемых, чтобы представить тип. Это может заставить получающееся значение быть отрицательным числом, даже при том, что символы представляют 16-разрядные значения целого без знака.

В сужающемся преобразовании числа с плавающей точкой к целочисленному типу, если число с плавающей точкой НЭН, результат преобразования 0 из соответствующего типа. Если число с плавающей точкой является слишком большим, чтобы быть представленным целочисленным типом, или является положительной бесконечностью, результатом является самое большое представимое значение целочисленного типа. Если число с плавающей точкой является слишком маленьким, чтобы быть представленным, или является отрицательной бесконечностью, результатом является самое маленькое представимое значение целочисленного типа. Иначе, результатом является число с плавающей точкой, округленное к нулю к целочисленному значению, используя режим раунда к нулю IEEE 754 (§2.4.3)

Сужающееся преобразование из double к float ведет себя в соответствии с IEEE 754. Результат правильно округляется, используя режим раунда-к-самому-близкому IEEE 754 (§2.4.3). Значение, слишком маленькое, чтобы быть представленным как a float преобразовывается в положительный или отрицательный нуль; значение, слишком большое, чтобы быть представленным как a float преобразовывается в положительную или отрицательную бесконечность. A double НЭН всегда преобразовывается в a float НЭН.

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

2.6.4 Расширение Ссылочных Преобразований

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

2.6.5 Сужение Ссылочных Преобразований

Следующие разрешенные преобразования вызывают сужающимися ссылочными преобразованиями:

Такие преобразования требуют, чтобы тест во время выполнения узнал, является ли фактическое ссылочное значение законным значением нового типа. Если это не, виртуальная машина Java бросает a ClassCastException.

2.6.6 Преобразование присвоения

Преобразование присвоения происходит, когда значение выражения присваивается переменной: тип выражения должен быть преобразован в тип переменной. Контексты присвоения позволяют использование преобразования идентификационных данных (§2.6.1), расширяющееся примитивное преобразование (§2.6.2), или расширяющееся ссылочное преобразование (§2.6.4). Кроме того, сужающееся примитивное преобразование (§2.6.3) может использоваться, если все следующие условия удовлетворяются:

Если тип выражения может быть преобразован в тип переменной преобразованием присвоения, мы говорим, что выражение (или его значение) присваиваемо переменной или, эквивалентно, что тип выражения является присвоением, совместимым с типом переменной.

Преобразование присвоения никогда не вызывает исключение. Значение типа примитива не должно быть присвоено переменной ссылочного типа. Значение ссылочного типа не должно быть присвоено переменной типа примитива. Значение типа boolean может быть присвоен только переменной ввести boolean. Значение нулевого типа может быть присвоено любому ссылочному типу.

Присвоение значения ссылочного типа времени компиляции S (источник) к переменной ссылочного типа времени компиляции T (цель) разрешается:

2.6.7 Преобразование Вызова метода

Преобразование вызова метода применяется к каждому значению аргумента в вызове конструктора или методе: тип выражения параметра должен быть преобразован в тип соответствующего параметра. Контексты вызова метода позволяют использование преобразования идентификационных данных (§2.6.1), расширяющееся примитивное преобразование (§2.6.2), или расширяющееся ссылочное преобразование (§2.6.4). Преобразования вызова метода определенно не включают неявное сужение целочисленных констант, которое является частью преобразования присвоения (§2.6.6).

2.6.8 Кастинг Преобразований

Преобразования кастинга более мощны чем присвоение или преобразования вызова метода, которым применяются к операнд оператора броска: тип выражения операнда должен быть преобразован в тип, явно названный оператором броска. Контексты кастинга позволяют использование преобразования идентификационных данных (§2.6.1), расширяющееся примитивное преобразование (§2.6.2), сужающееся примитивное преобразование (§2.6.3), расширяющееся ссылочное преобразование (§2.6.4), или сужающееся ссылочное преобразование (§2.6.5). Таким образом преобразования кастинга являются более содержащими чем преобразования вызова метода или присвоение: бросок может сделать любое разрешенное преобразование кроме преобразования строк.

Кастинг может преобразовать значение любого числового типа к любому другому числовому типу. Значение типа boolean не может быть брошен к другому типу. Значение ссылочного типа не может быть брошено к значению типа примитива.

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

2.6.9 Числовое Продвижение

Числовое продвижение применяется к операндам арифметического оператора. Числовые контексты продвижения позволяют использование преобразования идентификационных данных (§2.6.1) или расширяющегося примитивного преобразования (§2.6.2).

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

Оператор, который применяет унарное числовое продвижение единственному операнду числового типа, преобразовывает операнд типа byte, short, или char к int, и иначе оставляет операнд в покое. Операнды операторов сдвига продвигаются, независимо используя унарные числовые продвижения.

Когда оператор применяет двоичное числовое продвижение паре числовых операндов, следующие правила применяются, в порядке, используя расширяющееся преобразование (§2.6.2), чтобы преобразовать операнды по мере необходимости:


2.7 Имена и Пакеты

2.7.1 Имена

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

Простое имя является единственным идентификатором (§2.2). Полностью определенные имена обеспечивают доступ к элементам пакетов и ссылочных типов. Полностью определенное имя (§2.7.8) состоит из имени, "." маркера, и идентификатора.

Не все идентификаторы в программах Java являются частью имени. Идентификаторы также используются в объявлениях, где идентификатор определяет имя, которым объект будет известен в выражениях доступа к полю и выражениях вызова метода, и в метках оператора и break и continue операторы, которые обращаются к меткам оператора.

2.7.2 Пакеты

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

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

Имя компонента имени пакета или имя класса могли бы содержать символ, который не может по закону появиться в обычном каталоге файловой системы узла или имени файла: например, символ Unicode на системе, которая позволяет только символы ASCII в именах файлов.

Система Java должна поддерживать по крайней мере один неназванный пакет; это может поддерживать больше чем один неназванный пакет, но не обязано делать так. То, какие единицы компиляции находятся в каждом неназванном пакете, определяется хост-системой. Неназванные пакеты обеспечиваются Java преимущественно для удобства, разрабатывая маленькие или временные приложения или только начиная разработку.

import объявление позволяет тип, который, как объявляют в другом пакете, был известен простым именем, а не полностью определенным именем (§2.7.9) типа. Объявление импорта влияет только на описания типа единственной единицы компиляции. Единица компиляции автоматически импортирует каждый из public имена типов объявляются в предопределенном пакете java.lang.

2.7.3 Элементы

У пакетов и ссылочных типов есть элементы. Элементы пакета (§2.7.2) являются подпакетами и всем классом (§2.8) и интерфейс (§2.13) типы, объявленные во всех единицах компиляции пакета. Элементы ссылочного типа являются полями (§2.9) и методы (§2.10).

2.7.4 Элементы пакета

Элементы пакета являются его подпакетами и типами, объявленными в единицах компиляции пакета.

Вообще, подпакеты пакета определяются хост-системой. Однако, стандартный пакет java всегда имеет подпакеты lang, util, io, и net. Ни у каких двух отличных элементов того же самого пакета не может быть того же самого простого имени (§2.7.1), но у элементов различных пакетов может быть то же самое простое имя.

2.7.5 Элементы Типа класса

Элементы типа класса (§2.8) являются полями (§2.9) и методы (§2.10). Они включают элементы, наследованные от его прямого суперкласса (§2.8.3), если это имеет один, элементы, наследованные от каких-либо прямых суперинтерфейсов (§2.13.2), и каких-либо элементов, объявленных в теле класса. Нет никакого ограничения против поля и метода типа класса, имеющего то же самое простое имя.

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

2.7.6 Элементы Интерфейсного Типа

Элементы интерфейсного типа (§2.13) являются полями и методами. Элементы интерфейса являются элементами, наследованными от любых прямых суперинтерфейсов (§2.13.2) и элементами, объявленными в теле интерфейса.

2.7.7 Элементы Типа Массива

Элементы типа массива (§2.14) являются элементами, наследованными от его суперкласса, класса Object (§2.4.6), и поле length, который является константой (final) поле каждого массива.

2.7.8 Полностью определенные имена и Управление доступом

Полностью определенные имена (§2.7.1) являются средством доступа к элементам пакетов и ссылочных типов; связанные средства доступа включают выражения доступа к полю и выражения вызова метода. Все три синтаксически подобны в этом "." маркер кажется, предшествовавшим некоторой индикацией относительно пакета, введите, или выражение, имеющее тип и сопровождаемый идентификатором, который называет элемент пакета или типа. Они все вместе известны как конструкции для квалифицированного доступа.

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

Доступен ли пакет, определяется хост-системой.

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

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

Поле, метод, или конструктор класса могут быть объявлены, используя самое большее один из public, private, или protected ключевые слова. A public к элементу может получить доступ любой код Java. A private к элементу можно получить доступ только изнутри класса, который содержит его объявление. Элемент, который не объявляется public, protected, или private как говорят, имеет доступ по умолчанию и может быть получен доступ от, и только от, где угодно в пакете, в котором он объявляется.

A protected к элементу объекта может получить доступ только код, ответственный за реализацию того объекта. Быть точным, a protected к элементу можно получить доступ отовсюду в пакете, в котором он объявляется и, кроме того, к нему можно получить доступ изнутри любого объявления подкласса типа класса, который содержит его объявление, при условии, что определенным ограничениям повинуются.

2.7.9 Полностью определенные Имена

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


2.8 Классы

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

Тело класса объявляет элементы (поля и методы), статические инициализаторы, и конструкторы.

2.8.1 Имена классов

Если класс объявляется в именованном пакете с полностью определенным именем P, то у класса есть полностью определенное имя P.Идентификатор. Если класс находится в неназванном пакете, то у класса есть полностью определенный Идентификатор имени.

Два класса являются тем же самым классом (и поэтому тот же самый тип), если они загружаются тем же самым загрузчиком класса (§2.16.2), и у них есть то же самое полностью определенное имя (§2.7.9).

2.8.2 Модификаторы класса

Объявление класса может включать модификаторы класса. Класс может быть объявлен public, как обсуждено в §2.7.8.

abstract класс является классом, который является неполным, или рассмотренный неполным. Только abstract классы могут иметь abstract методы (§2.10.3), то есть, методы, которые объявляются, но еще не реализуются.

Класс может быть объявлен final если его определение полно, и никакие подклассы не требуются или требуются. Поскольку a final у класса никогда нет подклассов, методов a final класс не может быть переопределен в подклассе. Класс не может быть обоими final и abstract, потому что реализация такого класса никогда не могла завершаться.

Класс объявляется public сделать его тип доступным для пакетов кроме того, в котором это объявляется. A public класс доступен от других пакетов, используя или его полностью определенное имя или более короткое имя, создаваемое import объявление (§2.7.2), всякий раз, когда узел разрешает доступ к своему пакету. Если классу недостает public модификатор, доступ к объявлению класса ограничивается пакетом, в котором это объявляется.

2.8.3 Суперклассы и Подклассы

Дополнительное extends пункт в объявлении класса определяет прямой суперкласс текущего класса, класса, из реализации которого получается реализация текущего класса. Класс, как говорят, является прямым подклассом класса это extends. Только класс Object (у §2.4.6) нет никакого прямого суперкласса. Если extends пункт опускается от объявления класса, тогда суперкласс нового класса Object.

Отношение подкласса является переходным закрытием прямого отношения подкласса. Класс A является подклассом класса C, если A является прямым подклассом C, или если есть прямой подкласс B C, и класс A является подклассом Б. Класс А, как, говорят, суперкласс класса C всякий раз, когда C является подклассом A.

2.8.4 Элементы Класса

Элементы типа класса включают все следующее:

Элементы суперкласса, которые объявляются private не наследованы подклассами того класса. Элементы класса, которые не объявляются private, protected, или public не наследованы подклассами, объявленными в пакете кроме того, в котором объявляется класс. Конструкторы (§2.12) и статические инициализаторы (§2.11) не являются элементами и поэтому не наследованы.


2.9 Поля

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

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

2.9.1 Полевые Модификаторы

Поля могут быть объявлены public, protected, или private, как обсуждено в §2.7.8.

Если поле объявляется static, там существует точно одно воплощение поля, независимо от того сколько экземпляров (возможно нуль) класса может в конечном счете быть создано. A static поле, иногда называемое переменной класса, воплощается, когда класс инициализируется (§2.16.4).

Поле, которое не объявляется static вызывается переменной экземпляра. Всякий раз, когда новый экземпляр класса создается, новая переменная, связанная с тем экземпляром, создается для каждой переменной экземпляра, объявленной в том классе или в любом из его суперклассов.

Поле может быть объявлено final, когда его оператор объявления должен включать переменный инициализатор (§2.9.2). И класс и переменные экземпляра (static и не -static поля), может быть объявлен final. Однажды a final поле было инициализировано, оно всегда содержит то же самое значение. Если a final поле содержит ссылку на объект, тогда состояние объекта может быть изменено операциями на объекте, но поле будет всегда обращаться к тому же самому объекту.

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

Язык Java позволяет потокам что совместно используемые переменные доступа сохранять частные рабочие копии переменных; это позволяет более эффективную реализацию многократных потоков (§2.17). Эти рабочие копии должны быть согласованными с основными копиями в совместно используемой основной памяти только в предписанных точках синхронизации, а именно, когда объекты блокируются или разблокировались (§2.17). Как правило, чтобы гарантировать, что совместно используемые переменные последовательно и достоверно обновляются, поток должен гарантировать, что у него есть эксклюзивный доступ к таким переменным, получая блокировку, которая традиционно осуществляет взаимное исключение для тех совместно используемых переменных.

Java обеспечивает второй механизм, который более удобен в некоторых целях: поле может быть объявлено volatile, когда поток должен согласовать свою рабочую копию поля с основной копией каждый раз, когда это получает доступ к переменной. Кроме того операции на основных копиях одной или более энергозависимых переменных от имени потока выполняются основной памятью в точно порядке что поток, который требуют. A final поле не может также быть объявлено volatile.

2.9.2 Инициализация Полей

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


2.10 Метода

Метод объявляет исполняемый код, который может быть вызван, передавая постоянное число значений как параметры. Каждое объявление метода принадлежит некоторому классу. Класс наследовался от его прямого суперкласса (§2.8.3) и любых прямых суперинтерфейсов (§2.13.2) все доступные методы суперкласса и суперинтерфейсов с одним исключением: если имя объявляется как метод в новом классе, то никакой метод с той же самой подписью (§2.10.2) не наследован. Вместо этого недавно объявленный метод, как говорят, переопределяет любое такое объявление метода. Метод переопределения не должен конфликтовать с определением, которое он переопределяет, например, при наличии различного типа возврата. К переопределенным методам суперкласса можно получить доступ, используя выражение вызова метода, включающее super ключевое слово.

2.10.1 Формальные параметры

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

2.10.2 Подпись

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

2.10.3 Модификаторы метода

Модификаторы доступа public, protected, и private обсуждаются в §2.7.8.

abstract объявление метода представляет метод, поскольку элемент, обеспечивая его подпись (§2.10.2), возвращает тип, и throws пункт (если кто-либо), но не обеспечивает реализацию. Объявление abstract метод м. должен появиться в пределах abstract класс (вызывают это A). Каждый подкласс, который не является самостоятельно abstract должен обеспечить реализацию для м. Метод объявляется abstract не может также быть объявлен private, static, final, native, или synchronized.

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

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

Метод может быть объявлен final препятствовать тому, чтобы подклассы переопределили или скрыли это. A private метод и все методы объявляются в a final класс (§2.8.2) неявно final, потому что невозможно переопределить их. Если метод final или неявно final, компилятор или генератор кода времени выполнения могут безопасно "встроить" тело a final метод, заменяя вызов метода с кодом в его теле.

A synchronized метод получит блокировку монитора (§2.17) прежде, чем он выполнится. Для класса (static) метод, блокировка, связанная с объектом класса для класса метода, используется. Для метода экземпляра, блокировка, связанная с this (объект, для которого вызывается метод) используется. Та же самая блокировка на объект используется synchronized оператор.

Метод может быть объявлен native указать, что это реализуется в зависимом от платформы коде, обычно записанном в другом языке программирования, таком как C, C++, или ассемблер.


2.11 Статических Инициализатора

Любые статические инициализаторы, объявленные в классе, выполняются, когда класс инициализируется (§2.16.4) и, вместе с любыми полевыми инициализаторами (§2.9.2) для переменных класса, может использоваться, чтобы инициализировать переменные класса класса (§2.16.4).

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


2.12 Конструктора

Конструктор используется в создании объекта, который является экземпляром класса. Объявление конструктора похоже на объявление метода, у которого нет никакого типа результата. Конструкторы вызываются выражениями создания экземпляра класса (§2.16.6) преобразованиями и связями, вызванными оператором конкатенации строк +, и явными вызовами конструктора от других конструкторов; они никогда не вызываются выражениями вызова метода.

Доступом к и наследованием конструкторов управляют модификаторы доступа public, protected, и private (§2.7.8). Объявления конструктора не являются элементами. Они никогда не наследованы и поэтому не подвергаются сокрытию или переопределению.

Если тело конструктора не начинается с явного вызова конструктора, и объявляемый конструктор не является частью исконного класса Object, тогда тело конструктора, как неявно предполагает компилятор, начинается с вызова конструктора суперкласса"super();", вызов конструктора его прямого суперкласса, который не берет параметров.

Если класс не объявляет конструкторов, то конструктор по умолчанию, который не берет параметров, автоматически обеспечивается. Если объявляемый класс Object, тогда у конструктора по умолчанию есть пустое тело. Иначе, конструктор по умолчанию не берет параметров и просто вызывает конструктора суперкласса без параметров. Если класс объявляется public, тогда конструктору по умолчанию неявно дают модификатор доступа public. Иначе, конструктору по умолчанию подразумевал доступ по умолчанию никакой модификатор доступа (§2.7.8).

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


2.13 Интерфейса

Интерфейс является ссылочным типом, элементы которого являются константами и abstract методы. У этого типа нет никакой реализации, но иначе несвязанные классы могут реализовать его, обеспечивая реализации для abstract методы. Программы Java могут использовать интерфейсы, чтобы сделать это ненужным для связанных классов, чтобы совместно использовать общее abstract суперкласс или добавить методы к Object.

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

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

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

2.13.1 Интерфейсные Модификаторы

Интерфейсному объявлению могут предшествовать интерфейсные модификаторы public и abstract. Модификатор доступа public обсуждается в (§2.7.8). Каждый интерфейс неявно abstract. Все элементы интерфейсов неявно public.

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

2.13.2 Суперинтерфейсы

Если extends пункт обеспечивается, тогда объявляемый интерфейс расширяет каждый из других именованных интерфейсов, и поэтому наследовал методы и константы каждого из других именованных интерфейсов. Любой класс это implements объявленный интерфейс, как также полагают, реализует все интерфейсы, которые расширяет этот интерфейс и которые доступны для класса.

implements пункт в объявлении класса перечисляет имена интерфейсов, которые являются прямыми суперинтерфейсами объявляемого класса. Все интерфейсы в текущем пакете доступны. Интерфейсы в других пакетах доступны, если хост-система разрешает доступ к пакету, и интерфейс объявляется public.

Интерфейсный K типа является суперинтерфейсом типа класса C, если K является прямым суперинтерфейсом C; или если у C есть прямой суперинтерфейс J, у которого есть K как суперинтерфейс; или если K является суперинтерфейсом прямого суперкласса C. Класс, как говорят, реализует все свои суперинтерфейсы.

Нет никакого аналога класса Object для интерфейсов; то есть, в то время как каждый класс является расширением класса Object, нет никакого единственного интерфейса, которого все интерфейсы являются расширениями.

2.13.3 Интерфейсные Элементы

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

Интерфейсные элементы являются или полями или методами.

2.13.4 Интерфейсные (Постоянные) Поля

Каждое полевое объявление в теле интерфейса неявно static и final. У интерфейсов нет переменных экземпляра. Каждое полевое объявление в интерфейсе самостоятельно неявно public. Объявление константы в интерфейсе не должно включать ни один из модификаторов transient или volatile.

У каждого поля в теле интерфейса должно быть выражение инициализации, которое не должно быть константным выражением. Переменный инициализатор оценивается и присвоение, выполняемое точно однажды, когда интерфейс инициализируется (§2.16.4).

2.13.5 Интерфейсные (Абстрактные) Методы

Каждое объявление метода в теле интерфейса неявно abstract. Каждое объявление метода в теле интерфейса неявно public.

Метод, объявленный в интерфейсе, не должен быть объявлен static, потому что в Java static методы не могут быть abstract. Метод, объявленный в теле интерфейса, не должен быть объявлен native или synchronized, потому что те ключевые слова описывают свойства реализации, а не интерфейсные свойства; однако, метод, объявленный в интерфейсе, может быть реализован методом, который объявляется native или synchronized в классе, который реализует интерфейс. Метод, объявленный в теле интерфейса, не должен быть объявлен final; однако, можно быть реализован методом, который объявляется final в классе, который реализует интерфейс.

2.13.6 Переопределение, Наследование, и Перегрузка в Интерфейсах

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

Интерфейс наследовал от его прямых суперинтерфейсов все методы суперинтерфейсов, которые не переопределяются объявлением в интерфейсе.

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


2.14 Массива

Массивы Java являются объектами, динамически создаются, и могут быть присвоены переменным типа Object (§2.4.6). Все методы класса Object может быть вызван на массив.

Объект массива содержит много переменных. То число может быть нулем, когда массив, как говорят, пуст. У переменных, содержавшихся в массиве, нет никаких имен; вместо этого на них ссылаются выражения доступа массива, которые используют неотрицательные целочисленные индексные значения. Эти переменные вызывают компонентами массива. Если у массива есть n компоненты, мы говорим, что n является длиной массива.

Массив нулевых компонентов не является тем же самым как нулевой ссылкой (§2.4).

2.14.1 Типы массива

У всех компонентов массива есть тот же самый тип, названный компонентным типом массива. Если компонентный тип массива является T, то тип самого массива пишется T[].

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

Есть одна ситуация, в которой элемент массива может быть массивом: если тип элемента Object (§2.4.6), тогда некоторые или все элементы могут быть массивами, потому что каждый объект массива может быть присвоен переменной типа Object.

В Java, в отличие от C, массива char не a String (§2.4.6), и ни один a String ни массив char завершается 'u0000' ( NULСимвольный). Java String объект является неизменным (его значение никогда не изменяется), в то время как массив char имеет изменчивые элементы.

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

2.14.2 Переменные типа массив

Переменная типа массива содержит ссылку на объект. Объявление переменной типа массива не создает объект массива или выделяет любое место для компонентов массива. Это создает только переменную непосредственно, которая может содержать ссылку на массив.

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

Если у переменной типа массив v есть тип A[], где A является ссылочным типом, тогда v может содержать ссылку на любой тип B массива[], если B может быть присвоен (§2.6.6).

2.14.3 Создание массива

Массив создается выражением создания массива или инициализатором массива.

2.14.4 Доступ массива

К компоненту массива получают доступ, используя выражение доступа массива. Массивы могут быть индексированы int значения; short, byte, или char значения могут также использоваться, поскольку они подвергаются унарному числовому продвижению (§2.6.9) и становятся int значения.

Все массивы с 0 источниками. Массив с длиной n может быть индексирован целыми числами 0 через n - 1. Во время выполнения проверяются все доступы массива; попытка использовать индекс, который является меньше чем нуль или больше чем или равный длине массива, вызывает ArrayIndexOutOf-Bounds---Exception быть брошенным.


2.15 Исключения

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

Программы Java могут также выдать исключения явно, используя throw операторы. Это обеспечивает альтернативу старомодному стилю условий ошибки из-за неправильного обращения, возвращая отличенные ошибочные значения, такие как целочисленное значение -1, где отрицательная величина обычно не ожидалась бы.

Каждое исключение представляется экземпляром класса Throwable или один из его подклассов; такой объект может использоваться, чтобы перенести информацию от точки, в которой исключение происходит с обработчиком, который ловит это. Обработчики устанавливаются catch пункты try операторы. Во время процесса выдачи исключения виртуальная машина Java резко завершает, один за другим, любые выражения, операторы, метод и вызовы конструктора, статические инициализаторы, и полевые выражения инициализации, которые начали, но не завершили выполнение в текущем потоке. Этот процесс продолжается, пока обработчик не находится, который указывает, что это обрабатывает выданное исключение, называя класс исключения или суперкласс класса исключения. Если никакой такой обработчик не находится, то метод uncaught-Exception вызывается для ThreadGroup это - родитель текущего потока.

Механизм исключения Java интегрируется с моделью синхронизации Java (§2.17), так, чтобы блокировки были должным образом выпущены как synchronized операторы и вызовы synchronized методы завершаются резко.

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

2.15.1 Причины Исключений

Исключение выдается по одной из трех причин:

Исключения представляются экземплярами класса Throwable и экземпляры его подклассов. Эти классы являются, все вместе, классами исключений.

2.15.2 Обработка Исключения

Когда исключение выдается, управление передается от кода, который вызвал исключение к самому близкому динамически включение catch пункт a try оператор, который обрабатывает исключение.

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

Вызывающая сторона оператора или выражения зависит от того, где это происходит:

Ли деталь catch дескрипторы пункта исключение определяется, сравнивая класс объекта, который был брошен в объявленный тип параметра catch пункт. catch пункт обрабатывает исключение, если тип его параметра является классом исключения или суперклассом класса исключения. Эквивалентно, a catch пункт поймает любой объект исключения, который является instanceof объявленный тип параметра.

Передача управления, которая происходит, когда исключение выдается причины резкое завершение выражений и операторов до a catch с пунктом встречаются, который может обработать исключение; выполнение тогда продолжается, выполняя блок этого catch пункт. Код, который вызвал исключение, никогда не возобновляется.

Если нет catch пункт, обрабатывающий исключение, может быть найден, тогда текущий поток (поток, который встречался, исключение) завершается, но только в конце концов finally пункты были выполнены и метод uncaughtException был вызван для ThreadGroup это - родитель текущего потока.

В ситуациях, где это является требуемым, чтобы гарантировать, что один блок кода всегда выполняется за другим, даже если тот другой блок кода завершается резко, a try оператор с a finally пункт может использоваться. Если a try или catch блок в a try-finally или try-catch-finally оператор завершается резко, тогда finally пункт выполняется во время распространения исключения, даже если никакое соответствие catch пункт в конечном счете находится. Если a finally пункт выполняется из-за резкого завершения a try блок и finally сам пункт завершается резко, тогда причина резкого завершения try блок отбрасывается, и новая причина резкого завершения распространяется оттуда.

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

Асинхронные исключения редки в Java. Они происходят только в результате:

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

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

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

Все исключения в Java точны: когда передача управления имеет место, все эффекты выполняемых операторов и выражения, оцененные перед, точка, от которой выдается исключение, должно казаться, имела место. Никакие выражения, операторы, или части этого, которые происходят после точки, от которой выдается исключение, может казаться, не были оценены. Если оптимизированный код теоретически выполнил некоторые из выражений или операторов, которые следуют за точкой, в которой происходит исключение, такой код должен быть подготовлен скрыть это спекулятивное выполнение от видимого пользователем состояния программы Java.

2.15.3 Иерархия Исключения

Возможные исключения в программе Java организуются в иерархии классов, базировался в классе Throwable, прямой подкласс Object. Классы Exception и Error прямые подклассы Throwable. Класс RuntimeException прямой подкласс Exception.

Программы Java могут использовать существующие ранее классы исключений в throw операторы, или определяют дополнительные классы исключений, как подклассы Throwable или любого из его подклассов, как соответствующий. Чтобы использовать в своих интересах время компиляции Java, проверяя на обработчики исключений, это типично, чтобы определить самые новые классы исключений как проверенные классы исключений, определенно как подклассы Exception это не подклассы RuntimeException.

2.15.4 Классы Exception и RuntimeException

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

Класс RuntimeException подкласс класса Exception. Подклассы RuntimeException классы исключений непроверенные. Пакет java.lang определяет следующие стандартные исключения на этапе выполнения непроверенные:

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

} catch (Exception e) {
поймать все исключения, от которых восстановление может быть возможным, не фиксируя ошибки, от которых восстановление обычно не возможно. Пакет java.lang определяет все ошибочные классы, описанные здесь.

Виртуальная машина Java бросает объект, который является экземпляром подкласса LinkageError когда загрузка (§2.16.2), соединяясь (§2.16.3), или инициализация (§2.16.4) ошибка происходит:

Виртуальная машина Java бросает объект, который является экземпляром подкласса класса VirtualMachineError когда внутреннее ограничение ошибки или ресурса препятствует тому, чтобы это реализовало семантику Языка Java. Эта спецификация определяет следующие ошибки виртуальной машины:


2.16 Выполнения

Этот раздел определяет действия, которые происходят во время выполнения программы Java. Это организуется вокруг жизненного цикла виртуальной машины Java и классов, интерфейсов, и возражает, что формируют программу Java. Это определяет подробные процедуры, используемые в запуске виртуальной машины (§2.16.1), класс и интерфейсный тип, загружающийся (§2.16.2), соединяясь (§2.16.3), и инициализация (§2.16.4). Это тогда определяет процедуры для создания новых экземпляров класса (§2.16.6). Это заканчивается, описывая разгрузку классов (§2.16.8) и процедура, сопровождаемая, когда виртуальная машина выходит (§2.16.9).

2.16.1 Запуск Виртуальной машины

Виртуальная машина Java запускает выполнение, вызывая метод main из некоторого указанного класса, передавая это единственный параметр, который является массивом строк. Это заставляет указанный класс быть загруженным (§2.16.2), соединялся (§2.16.3) с другими типами, которые это использует, и инициализированный (§2.16.4). Метод main должен быть объявлен public, static, и void.

Способ, которым начальный класс определяется к виртуальной машине Java, выходит за рамки этой спецификации, но это типично в средах узла, которые используют командные строки для полностью определенного имени класса, который будет определен как параметр командной строки и для последующих параметров командной строки, которые будут использоваться в качестве строк, которые будут обеспечены как параметр методу main. Например, в реализации JDK Sun на UNIX, командной строке

    java Terminator Hasta la vista Baby!
запустит виртуальную машину Java, вызывая метод main из класса Terminator (класс в неназванном пакете), передавая это массив, содержащий четыре строки "Hasta", "la", "vista", и "Baby!".

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

Начальная попытка выполнить метод main из класса Terminator обнаруживает что класс Terminator не загружается - то есть, виртуальная машина в настоящий момент не содержит двоичное представление для этого класса. Виртуальная машина тогда использует a ClassLoader (§2.16.2), чтобы попытаться найти такое двоичное представление. Если этот процесс перестал работать, ошибка бросается. Этот процесс загрузки описывается далее в (§2.16.2).

После Terminator загружается, это должно быть инициализировано прежде main может быть вызван, и тип (класс или интерфейс) должен всегда соединяться прежде, чем это будет инициализировано. Соединение включает проверку, подготовку, и (дополнительно) разрешение. Соединение описывается далее в §2.16.3.

Проверка проверяет что загруженное представление Terminator хорошо формируется, с надлежащей таблицей символов. Проверка также проверяет, что код, который реализует Terminator повинуется семантическим требованиям виртуальной машины Java. Если проблема обнаруживается во время проверки, ошибка бросается. Проверка описывается далее в §2.16.3.

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

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

Шаг разрешения является дополнительным во время начального редактирования. Реализация может разрешить символьную ссылку от класса или интерфейса, который соединяется очень рано, даже на грани разрешения всех символьных ссылок от классов и интерфейсов, на которые далее ссылаются, рекурсивно. (Это разрешение может привести к ошибкам от дальнейшей загрузки и соединения шагов.) Этот выбор реализации представляет одно экстремальное значение и подобен виду статического редактирования, которое было сделано много лет в простых реализациях языка C.

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

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

Процесс разрешения описывается далее в §2.16.3.

В нашем рабочем примере виртуальная машина все еще пытается выполнить метод, основной из класса Terminator. Это - предпринятое активное использование (§2.16.4) класса, который разрешается, только если класс был инициализирован.

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

Если класс Terminator имеет другой класс Super как его суперкласс, тогда Super должен быть инициализирован прежде Terminator. Это требует загрузки, проверки, и подготовки Super, если это не было уже сделано, и, в зависимости от реализации, может также включить разрешение символьных ссылок от Super и так далее, рекурсивно.

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

Процесс инициализации описывается далее в §2.16.4.

Наконец, после завершения инициализации для класса Terminator (во время которого другая последовательная загрузка, соединение, и инициализация, возможно, произошли), метод main из Terminator вызывается.

2.16.2 Загрузка

Загрузка обращается к процессу обнаружения двоичной формы класса или интерфейсного типа с определенным именем, возможно вычисляя это на лету, но более обычно получая двоичное представление, ранее вычисленное из исходного кода компилятором и построением, из той двоичной формы, a Class объект представить класс или интерфейс. Двоичный формат класса или интерфейса обычно class формат файла (см. Главу 4, "Формат файла класса").

Процесс загрузки реализуется классом ClassLoader и его подклассы. Различные подклассы ClassLoader может реализовать различные политики загрузки. В частности загрузчик класса может кэшировать двоичные представления классов и интерфейсов, выбрать их с упреждением основанный на ожидаемом использовании, или загрузить группу связанных классов вместе. Эти действия, возможно, не абсолютно прозрачны к рабочему приложению Java, если, например, недавно скомпилированная версия класса не находится, потому что более старая версия кэшируется загрузчиком класса. Это - ответственность загрузчика класса, однако, чтобы отразить загружающиеся ошибки только в точках в программе, где они, возможно, возникли, не выбирая с упреждением или групповая загрузка.

Если ошибка происходит во время загрузки класса, то экземпляр одного из следующих подклассов класса LinkageError будет брошен в любую точку в программе Java, которая (прямо или косвенно) использует тип:

2.16.3 Соединение: Проверка, Подготовка, и Разрешение

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

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

Например, реализация может хотеть разрешать каждую символьную ссылку в классе или взаимодействовать через интерфейс индивидуально, только когда это используется (ленивое или последнее разрешение), или разрешить их внезапно, например, в то время как класс проверяется (статическое разрешение). Это означает, что процесс разрешения может продолжаться в некоторых реализациях, после того, как класс или интерфейс был инициализирован.

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

Если ошибка происходит во время проверки, то экземпляр следующего подкласса класса LinkageError будет брошен в точку в программе Java, которая заставила класс быть проверенным:

Подготовка включает создание статических полей для класса или интерфейса и инициализации таких полей к стандартным значениям по умолчанию (§2.5.1). Это не требует выполнения любого кода Java; явные инициализаторы для статических полей выполняются как часть инициализации (§2.16.4), не подготовка.

Реализации Java должны обнаружить следующую ошибку во время подготовки:

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

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

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

Если ошибка происходит во время разрешения, то экземпляр одного из следующих подклассов класса IncompatibleClassChangeError, или некоторого другого подкласса, или IncompatibleClassChangeError непосредственно (который является подклассом класса Linkage-Error) может быть брошен в любую точку в программе Java, которая использует символьную ссылку на тип:

2.16.4 Инициализация

Инициализация класса состоит из выполнения его статических инициализаторов (§2.11) и инициализаторов для статических полей (§2.9.2) объявленный в классе. Инициализация интерфейса состоит из выполнения инициализаторов для полей, объявленных в интерфейсе (§2.13.4).

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

Класс или интерфейсный тип T будут инициализированы при его первом активном использовании, которое происходит если:

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

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

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

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

Инициализация интерфейса не делает, себя, требует инициализации любого из ее суперинтерфейсов.

2.16.5 Подробная Процедура Инициализации

Поскольку Java многопоточен, инициализация класса или интерфейса требует осторожной синхронизации, так как некоторый другой поток может пытаться инициализировать тот же самый класс или интерфейс одновременно. Есть также возможность, что инициализацию класса или интерфейса можно требовать рекурсивно как часть инициализации того класса или интерфейса; например, переменный инициализатор в классе A мог бы вызвать метод несвязанного класса B, который мог бы поочередно вызвать метод класса A. Реализация виртуальной машины Java ответственна за то, чтобы заботиться о синхронизации и рекурсивной инициализации при использовании следующей процедуры. Это предполагает что Class объект был уже проверен и подготовлен, и что Class объект содержит состояние, которое может указывать на одну из четырех ситуаций:

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

  1. Синхронизируйтесь на Class объект, который представляет класс или интерфейс, который будет инициализирован. Это включает ожидание, пока текущий поток не может получить блокировку для того объекта (§8.13).
  2. Если инициализация происходит для класса или интерфейса некоторым другим потоком, то wait на этом Class объект (который временно выпускает блокировку). Когда текущий поток просыпается от wait, повторите этот шаг.
  3. Если инициализация происходит для класса или интерфейса текущим потоком, то это должно быть рекурсивным запросом на инициализацию. Выпустите блокировку на Class возразите и полный обычно.
  4. Если класс или интерфейс были уже инициализированы, то никакое дальнейшее действие не требуется. Выпустите блокировку на Class возразите и полный обычно.
  5. Если Class объект находится в ошибочном состоянии, тогда инициализация не возможна. Выпустите блокировку на Class объект и бросок a NoClassDefFoundError.
  6. Иначе, запишите факт та инициализация Class объект теперь происходит текущим потоком, и выпустите блокировку на Class объект.
  7. Затем, если Class объект представляет класс, а не интерфейс, и суперкласс этого класса еще не был инициализирован, тогда рекурсивно выполните эту всю процедуру для суперкласса. В случае необходимости проверьте и подготовьте суперкласс сначала. Если инициализация суперкласса завершается резко из-за выданного исключения, то заблокируйте это Class объект, маркируйте это ошибочным, уведомьте все потоки ожидания, выпустите блокировку, и завершитесь резко, выдавая то же самое исключение, которое следовало из инициализации суперкласса.
  8. Затем, выполните или инициализаторы переменной класса и статические инициализаторы класса, или полевые инициализаторы интерфейса, в текстовом порядке, как если бы они были единственным блоком, за исключением того, что final static переменные и поля интерфейсов, значения которых являются константами времени компиляции, инициализируются сначала.
  9. Если выполнение инициализаторов обычно завершается, то заблокируйте это Class объект, маркируйте, он полностью инициализировал, уведомьте все потоки ожидания, выпустите блокировку, и обычно завершайте эту процедуру.
  10. Иначе, инициализаторы, должно быть, завершились резко, выдавая некоторое исключение E. Если класс E не Error или один из его подклассов, затем создайте новый экземпляр класса ExceptionInInitializerError, с E как параметр, и использование этот объект вместо E в следующем шаге. Но если новый экземпляр ExceptionInInitializerError не может быть создан потому что OutOfMemoryError происходит, тогда вместо этого используйте OutOfMemoryError объект вместо E в следующем шаге.
  11. Заблокируйте Class объект, маркируйте это ошибочным, уведомьте все потоки ожидания, выпустите блокировку, и завершите эту процедуру резко с причиной E или ее заменой как определено в предыдущем шаге.
В некоторых ранних реализациях Java исключение во время класса initializa-tion было проигнорировано, вместо того, чтобы вызвать ExceptionInInitializerError как описано здесь.

2.16.6 Создание Новых Экземпляров Класса

Новый экземпляр класса явно создается, когда одна из следующих ситуаций происходит:

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

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

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

  1. Присвойте параметры за конструктора к недавно создаваемым переменным параметра для этого вызова конструктора.
  2. Если этот конструктор начинает с явного вызова конструктора другого конструктора в том же самом классе (использование this), затем оцените параметры и обработайте тот вызов конструктора, рекурсивно используя эти те же самые пять шагов. Если тот вызов конструктора завершается резко, то эта процедура завершается резко по той же самой причине. Иначе, продолжайте с шагом 5.
  3. Этот конструктор не начинает с явного вызова конструктора другого конструктора в том же самом классе (использование this). Если этот конструктор для класса кроме Object, тогда этот конструктор начнет с явного или неявного вызова конструктора суперкласса (использование super). Оцените параметры и обработайте тот вызов конструктора суперкласса, рекурсивно используя эти те же самые пять шагов. Если тот вызов конструктора завершается резко, то эта процедура завершается резко по той же самой причине. Иначе, продолжайте с шагом 4.
  4. Выполните инициализаторы переменной экземпляра для этого класса, присваивая их значения соответствующим переменным экземпляра, в слева направо порядок, в котором они появляются дословно в исходном коде для класса. Если выполнение любого из этих результатов инициализаторов в исключении, то никакие дальнейшие инициализаторы не обрабатываются и эта процедура, завершается резко с тем же самым исключением. Иначе, продолжайте с шагом 5. (В некоторых ранних реализациях Java, компилятор, неправильно опущенный код, чтобы инициализировать поле, если полевое выражение инициализатора было константным выражением, значение которого было равно значению инициализации по умолчанию для его типа. Это было ошибкой.)
  5. Выполните остальную часть тела этого конструктора. Если то выполнение завершается резко, то эта процедура завершается резко по той же самой причине. Иначе, эта процедура обычно завершается.
В отличие от C++, язык Java не определяет, что измененные правила для метода диспетчеризируют во время создания нового экземпляра класса. Если методы вызываются, которые переопределяются в подклассах в инициализируемом объекте, то эти методы переопределения используются, даже прежде, чем новый объект полностью создается.

2.16.7 Завершение Экземпляров Класса

Класс Object имеет a protected метод вызывают finalize; этот метод может быть переопределен другими классами. Определенное определение finalize это может быть вызвано для объекта, вызывается финализатором того объекта. Прежде, чем хранение для объекта исправляется сборщиком "мусора", виртуальная машина Java вызовет финализатор того объекта.

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

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

finalize метод объявляется в классе Object не предпринимает мер. Однако, факт тот класс Object объявляет a finalize метод означает что finalize метод для любого класса может всегда вызывать finalize метод для его суперкласса, который является обычно хорошей практикой. (В отличие от конструкторов, финализаторы автоматически не вызывают финализатор для суперкласса; такой вызов должен быть кодирован явно.)

Для эффективности реализация может отследить классы, которые не переопределяют finalize метод класса Object, или переопределите это тривиальным способом, такой как

    protected void finalize() { super.finalize(); }
Мы поощряем реализации обрабатывать такие объекты как наличие финализатора, который не переопределяется, и завершить их более эффективно.

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

Виртуальная машина Java не налагает упорядочивания на finalize вызовы метода. Финализаторы можно вызвать в любом порядке, или даже одновременно.

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

2.16.8 Завершение и Разгрузка Классов и Интерфейсов

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

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

Если класс объявляет метод класса classFinalize это не берет параметров, и не возвращает результата:

    static void classFinalize() { . . . }
тогда этот метод будет вызван прежде, чем класс разгружается. Как finalize метод для объектов, этот метод будет автоматически вызван только однажды. Этот метод может дополнительно быть объявлен private, protected, или public.

2.16.9 Выход Виртуальной машины

Виртуальная машина Java завершает все свое действие и выходит, когда одна из двух вещей происходит:

Программа Java может определить, что финализаторы всех объектов, у которых есть финализаторы, которые не были автоматически вызваны, должны быть выполнены перед выходами виртуальной машины. Это делается, вызывая метод runFinalizersOnExit из класса System с параметром true.3 Значение по умолчанию не должно выполнить финализаторы на выходе, и это поведение может быть восстановлено, вызывая runFinalizersOnExit с параметром false. Вызов runFinalizersOnExit метод разрешается, только если вызывающей стороне позволяют exit, и иначе отклоняется менеджером безопасности.


2.17 Потока

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

Любой поток может быть отмечен как поток демона. Когда код, работающий в некотором потоке, создает новое Thread объект, тот новый поток первоначально отмечается как поток демона, если и только если поток создания является потоком демона. Программа может измениться, является ли определенный поток потоком демона, вызывая -setDaemon метод в классе Thread. Виртуальная машина Java первоначально запускает с единственным потоком недемона, который обычно вызывает метод main из некоторого класса. Виртуальная машина может также создать другие потоки демона во внутренних целях. Виртуальная машина Java выходит, когда все потоки недемона умерли (§2.16.9).

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

synchronized оператор выполняет два специальных действия, относящиеся только к многопоточной работе:

  1. После вычислений ссылки на объект, но прежде, чем выполнить его тело, это блокирует блокировку, связанную с объектом.
  2. После того, как выполнение тела завершилось, или обычно или резко, это разблокировало ту же самую блокировку. Как удобство, может быть объявлен метод synchronized; такой метод ведет себя, как будто его тело содержалось в a synchronized оператор.
Методы wait, notify, и notifyAll из класса Object поддерживайте эффективную передачу управления от одного потока до другого. Вместо того, чтобы просто "вращаться" (неоднократно блокировка и разблокирование объекта видеть, изменилось ли некоторое внутреннее состояние), который использует вычислительное усилие, поток может приостановить себя использование wait до тех пор, пока другой поток пробуждает это использование notify или notifyAll. Это является особенно соответствующим в ситуациях, где у потоков есть отношение производителя-потребителя (активно сотрудничающий на общей цели), а не отношение взаимного исключения (пытающийся избежать конфликтов, совместно используя общий ресурс).

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

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

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

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

Детали взаимодействия потоков с основной памятью, и таким образом друг с другом, обсуждаются подробно в Главе 8, "Потоки и Блокировки."


1 Примечание, что локальная переменная не инициализируется на ее создании, и, как только полагают, содержит значение, как только это присваивается (§2.5.1).

2 завершения Класса и разгрузка не реализуются с выпуска 1.0.2 JDK Sun.

3 метод runFinalizersOnExit не реализуется в выпуске 1.0.2 JDK Sun.


Содержание | Предыдущий | Следующий | Индекс

Спецификация Виртуальной машины Java

Авторское право © 1996, 1997 Sun Microsystems, Inc. Все права защищены
Пожалуйста, отправьте любые комментарии или исправления к jvm@java.sun.com

free hit counter