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


ГЛАВА 2

Понятия Языка программирования Java


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

Контент этой главы был сжат из первого выпуска Спецификации языка JavaTM, Джеймсом Гослингом, Биллом Джоем, и Читателями Гая Стиле.1, знакомыми с языком программирования Java, но не со Спецификацией языка JavaTM, должен, по крайней мере, просмотреть эту главу для терминологии, которую это представляет. Любые несоответствия между этой главой и Спецификацией языка JavaTM должны быть разрешены в пользу Спецификации языка JavaTM.

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


2.1 Unicode

Программы, записанные в языке программирования Java, поддерживаемом выпуском 1.1.7 JDK и Java 2 платформы, v1.2 используют кодировку символов Unicode, версию 2.1, как определено в Стандарте Unicode, Версии 2.0, ISBN 0-201-48345-9, и информации об обновлении для Версии 2.1 Стандарта Unicode, доступного в http:// www.unicode.org. Программы, записанные в языке программирования Java используемая версия 2.0.14 Стандарта Unicode в JDK, выпускают 1.1 до 1.1.6 и используемая версия 1.1.5 Стандарта Unicode в выпуске 1.0 JDK.

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


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

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

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

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


2.3 Литералы

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

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


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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

2.4.3 Типы с плавающей точкой, Наборы значений, и Значения

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

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

Конечные ненулевые значения любого набора значений с плавающей точкой могут все быть выражены в форме s · м. · 2 (e-N + 1), где s +1 или-1, м. является положительным целым числом меньше чем 2N, и e является целым числом между Эмином = - (2 K - 1-2) и Emax = 2 K - 1-1, включительно, и где N и K являются параметрами, которые зависят от набора значений. Некоторые значения могут быть представлены в этой форме больше чем одним способом; например, если значение v в наборе значений могло бы быть представлено в этой форме, используя определенные значения для s, м., и e, затем если бы это произошло, которым м. был даже, и e составлял меньше чем 2 k-1, то можно было разделить на два м. и увеличить e на 1, чтобы произвести второе представление для того же самого значения v. Представление в этой форме вызывают нормализованное если м. 2N-1; иначе представление, как говорят, денормализовывается. Если значение в наборе значений не может быть представлено таким способом, которым м. 2N-1, то значение, как говорят, является денормализованным значением, потому что у этого нет никакого нормализованного представления.

Ограничения на параметры N и K (и на полученные параметры Эмин и Эмэкс) для этих требуемых двух и два дополнительных набора значений с плавающей точкой получаются в итоге в Таблице 2.1.

Параметр плавание "пустите в ход расширенную экспоненту" двойной "удвойте расширенную экспоненту"
N 24 24 53 53
K 8 11 11 15
Emax +127 +1023 +1023 +16383
Эмин -126 -1022 -1022 -16382


Где один или оба набора значений расширенной экспоненты поддерживаются реализацией, затем для каждого поддерживаемого набора значений расширенной экспоненты есть определенный зависящий от реализации постоянный K, значение которого ограничивается Таблицей 2.1; это значение K поочередно диктует значения для Эмина и Эмэкса.

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

Отметьте, что ограничения в Таблице 2.1 разрабатываются так, чтобы каждый элемент набора значений плавающего был обязательно также элементом набора значений "расширенная экспонента плавающая", двойной набор значений, и набор значений "двойная расширенная экспонента". Аналогично, каждый элемент двойного набора значений является обязательно также элементом набора значений "двойная расширенная экспонента". Каждый набор значений расширенной экспоненты имеет больший диапазон значений экспоненты чем соответствующий стандартный набор значений, но не имеет большей точности.

Элементы набора значений плавающего являются точно значениями, которые могут быть представлены, используя единственный формат с плавающей точкой, определенный в стандарте IEEE 754, за исключением того, что есть только одно значение НЭН (IEEE 754 определяет 224 - 2 отличных значения НЭН). Элементы двойного набора значений являются точно значениями, которые могут быть представлены, используя двойной формат с плавающей точкой, определенный в стандарте IEEE 754, за исключением того, что есть только одно значение НЭН (IEEE 754 определяет 253 - 2 отличных значения НЭН). Отметьте, однако, что элементы "плавания, расширенная экспонента" и наборы значений "двойная расширенная экспонента", определенная здесь, не соответствуют значениям, которые могут быть представлены, используя IEEE 754 единственные расширенные и двойные расширенные форматы, соответственно.

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

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

На сравнении положительный нулевой и отрицательный нуль равен; таким образом результатом выражения 0.0 ==-0.0 является истина, и результатом 0.0>-0.0 является ложь. Но другие операции могут отличить положительный и отрицательный нуль; например, у 1.0/0.0 есть значение положительная бесконечность, в то время как значение 1.0/-0.0 является отрицательной бесконечностью.

НЭН неупорядочивают, таким образом, числовые операторы сравнения <<=>, и> = возвращают false, если или или оба операнда НЭН. Оператор равенства == возвращает false, если любым операндом является НЭН, и оператор неравенства! = возвращает true, если любым операндом является НЭН. В частности x! = x является истиной, если и только если x является НЭН, и (x <y) ==! (x> =y), будет ложь, если x или y будет НЭН.

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

2.4.7 Класс Object

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

2.4.8 Класс String

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

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

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


2.5 Переменные

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

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

  1. Переменная класса является полем типа класса, объявленного, используя ключевое слово static (§2.9.1) в пределах объявления класса, или с или без ключевого слова static в интерфейсном объявлении. Переменные класса создаются, когда класс или интерфейс загружаются (§2.17.2) и инициализируются на создании к значениям по умолчанию (§2.5.1). Переменная класса эффективно прекращает существование, когда ее класс или интерфейс разгружаются (§2.17.8).

  2. Переменная экземпляра является полем, объявленным в пределах объявления класса, не используя ключевое слово static (§2.9.1). Если у класса T есть поле a, которое является переменной экземпляра, то новая переменная экземпляра создаваемого и инициализированного к значению по умолчанию (§2.5.1) как часть каждого недавно создаваемого объекта класса T или любого класса, который является подклассом T. Переменная экземпляра эффективно прекращает существование, когда, объектом которого это - поле, больше не ссылается, после любого необходимого завершения объекта был завершен (§2.17.7).

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

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

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

  6. Переменная параметра обработчика исключений создается каждый раз, когда исключение поймано a catch пункт a try оператор (§2.16.2). Новая переменная инициализируется с фактическим объектом, связанным с исключением (§2.16.3). Параметр обработчика исключений эффективно прекращает существование когда выполнение блока, связанного с catch пункт (§2.16.2) полон.

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

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

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

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

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

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

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

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

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


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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

2.6.6 Преобразование Набора значений

Преобразование набора значений является процессом отображения значения с плавающей точкой от одного набора значений (§2.4.3) другому, не изменяя его тип.

Для каждой работы в выражении, которое не строго FP (§2.18), преобразование набора значений позволяет реализации языка программирования Java выбирать между двумя опциями:

В пределах строгого FP выражения преобразование набора значений не обеспечивает вариантов; каждая реализация должна вести себя таким же образом:

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

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

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

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

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

Если тип переменной float или double, тогда преобразование набора значений (§2.6.6) применяется после преобразования типов:

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

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

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

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

Если тип выражения параметра является или плаванием или двойной, то преобразование набора значений (§2.6.6) применяется после преобразования типов:

2.6.9 Кастинг Преобразования

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

Преобразование набора значений (§2.6.6) применяется после преобразования типов.

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

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

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

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

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

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

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

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


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

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

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

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

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

2.7.2 Пакеты

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

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

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

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

2.7.3 Элементы

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

2.7.3.1 Элементы Пакета

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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


2.8 Классы

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

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

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

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

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

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

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

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

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

Класс может быть объявлен strictfp указать, что все выражения в методах класса строги FP (§2.18), объявляются ли сами методы строгие FP.

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

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

Дополнительное extends пункт в объявлении класса определяет прямой суперкласс текущего класса, класса, из реализации которого получается реализация текущего класса. Класс, как говорят, является прямым подклассом класса это extends. Только класс Object (у §2.4.7) нет никакого прямого суперкласса. Если 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.4.3); точно так же значение, сохраненное в поле двойного типа, всегда является элементом двойного набора значений. Не разрешается для поля плавания типа содержать элемент набора значений "расширенная экспонента плавающая", которая не является также элементом набора значений плавающего, ни для поля типа, двойного, чтобы содержать элемент набора значений "двойная расширенная экспонента", которая не является также элементом двойного набора значений.

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

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

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

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

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

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

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

Альтернативно, поле может быть объявлено 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.4.3); точно так же параметр метода типа, двойного всегда, содержит элемент двойного набора значений. Не разрешается для параметра метода плавания типа содержать элемент набора значений "расширенная экспонента плавающая", которая не является также элементом набора значений плавающего, ни для параметра метода типа, двойного, чтобы содержать элемент набора значений "двойная расширенная экспонента", которая не является также элементом двойного набора значений.

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

2.10.2 Сигнатура метода

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

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

Модификаторы доступа public, protected, и private обсуждаются в Разделе 2.7.4.

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

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

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

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

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

Метод может быть объявлен strictfp указать, что все выражения в методе строги FP (§2.18).

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


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

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

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


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

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

Объявления конструктора не являются элементами. Они никогда не наследованы и поэтому не подвергаются сокрытию или переопределению.

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

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

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

2.12.1 Модификаторы конструктора

Доступом к конструкторам управляют модификаторы доступа public, protected, и private (§2.7.4).

Конструктор не может быть abstract, static, final, native, или synchronized. Конструктор, как могут объявлять, не strictfp. Этим различием в определениях для модификаторов метода (§2.10.3) и модификаторов конструктора является намеренное проектное решение языка; это эффективно гарантирует, что конструктор строг FP (§2.18), если и только если его класс строг FP, так сказать.


2.13 Интерфейса

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

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

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

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

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

Интерфейсному объявлению могут предшествовать интерфейсные модификаторы public, strictfp, и abstract. Модификатор доступа public обсуждается в (§2.7.4). Каждый интерфейс неявно 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.3.1 Интерфейсные (Постоянные) Поля

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

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

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

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

Метод, объявленный в теле интерфейса, не должен быть объявлен static, потому что static методы не могут быть abstract.

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

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

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

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

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


2.14 Вложенных Класса и Интерфейсы

Выпуск 1.1 JDK добавленные вложенные классы и интерфейсы к языку программирования Java. Вложенные классы и интерфейсы иногда упоминаются как внутренние классы и интерфейсы, которые являются одним видом вложенных классов и интерфейсов. Однако, вложенные классы и интерфейсы также охватывают вложенные высокоуровневые классы и интерфейсы, которые не являются внутренними классами или интерфейсами.

Полная спецификация вложенных классов и интерфейсов будет опубликована во втором выпуске Спецификации языка JavaTM. До тех пор заинтересованные люди должны обратиться к Внутренней Спецификации Классов, которая может быть найдена в http://java.sun.com/products/jdk/1.1/docs/guide/innerclasses/spec/innerclasses.doc.html.


2.15 Массива

Массивы являются объектами, динамически создаются, и могут быть присвоены переменным типа Object (§2.4.7). Все методы на массивах унаследованы от класса Object кроме clone метод, который выстраивает переопределение. Все массивы реализуют интерфейсы Cloneable и java.io.Serializable.

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

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

Компонент массива плавания типа всегда является элементом набора значений плавающего (§2.4.3); точно так же компонент двойного типа всегда является элементом двойного набора значений. Компонент плавания типа, возможно, не элемент набора значений "расширенная экспонента плавающая", если это не также элемент набора значений плавающего. Компонент двойного типа, возможно, не элемент набора значений "двойная расширенная экспонента", если это не также элемент двойного набора значений.

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

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

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

Есть три ситуации, в которых элемент массива может быть массивом: если тип элемента имеет тип Object (§2.4.7), Cloneable, или java.io.Serializable, тогда некоторые или все элементы могут быть массивами, потому что каждый объект массива может быть присвоен переменной одного из тех типов.

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

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

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

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

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

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

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

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

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

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

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


2.16 Исключения

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

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

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

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

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

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

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

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

  2. A throw оператор выполнялся.

  3. Асинхронное исключение произошло потому что:

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

2.16.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 блок отбрасывается, и новая причина резкого завершения распространяется оттуда.

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

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

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

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

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

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

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

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

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

2.16.4 Классы Exception и RuntimeException

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

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

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

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

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

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


2.17 Выполнения

Этот раздел определяет действия, которые происходят во время выполнения программы. Это организуется вокруг жизненного цикла виртуальной машины Java и классов, интерфейсов, и возражает, что формируют программу. Это определяет подробные процедуры, используемые в запуске виртуальной машины (§2.17.1), класс и интерфейсный тип, загружающийся (§2.17.2), соединяясь (§2.17.3), и инициализация (§2.17.4). Это тогда определяет процедуры для создания новых экземпляров класса (§2.17.6). Это заканчивается, описывая разгрузку классов (§2.17.8) и процедура, сопровождаемая, когда виртуальная машина выходит (§2.17.9).

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

2.17.2 Загрузка

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Вызов определенных методов в классах библиотеки (§3.12) также вызывает класс или интерфейсную инициализацию. См. Java спецификации библиотеки классов 2 платформ (например, класс Class и пакет java.lang.reflect) для деталей.

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

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

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

Инициализация класса или интерфейса требует осторожной синхронизации, так как некоторый другой поток может пытаться инициализировать тот же самый класс или интерфейс одновременно. Есть также возможность, что инициализацию класса или интерфейса можно требовать рекурсивно как часть инициализации того класса или интерфейса; например, переменный инициализатор в классе 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 исключение во время инициализации класса было проигнорировано вместо того, чтобы позволить этому вызывать ExceptionInInitializerError как описано здесь.

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

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

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

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

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

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

  1. Присвойте параметры за конструктора к недавно создаваемым переменным параметра для этого вызова конструктора.

  2. Если этот конструктор начинает с явного вызова конструктора другого конструктора в том же самом классе (использование this), затем оцените параметры и обработайте тот вызов конструктора, рекурсивно используя эти те же самые пять шагов. Если тот вызов конструктора завершается резко, то эта процедура завершается резко по той же самой причине. Иначе, продолжайте с шагом 5.

  3. Если этот конструктор не начинает с явного вызова конструктора другого конструктора в том же самом классе (использование this) и находится в классе кроме Object, тогда этот конструктор начнет с явного или неявного вызова конструктора суперкласса (использование super). Оцените параметры и обработайте тот вызов конструктора суперкласса, рекурсивно используя эти те же самые пять шагов. Если тот вызов конструктора завершается резко, то эта процедура завершается резко по той же самой причине. Иначе, продолжайте с шагом 4.

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

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

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

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

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

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

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

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

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

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

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

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

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

Класс или интерфейс могут быть разгружены, если и только если его загрузчик класса недостижим. Загрузчик класса начальной загрузки всегда достижим; в результате системные классы никогда не могут разгружаться.

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

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

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


2.18 строгих FP Выражения

Если тип выражения является плаванием или двойной, то есть вопрос относительно того, из чего может быть оттянут набор значений (§2.4.3) значение выражения. Этим управляют правила преобразования набора значений (§2.6.6); эти правила поочередно зависят от того, строго ли выражение FP.

Каждое константное выражение времени компиляции строго FP. Если выражение не является константным выражением времени компиляции, то рассмотрите все объявления класса, интерфейсные объявления, и объявления метода, которые содержат выражение. Если какое-либо такое объявление переносит strictfp модификатор, то выражение строго FP.

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

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


2.19 Потока

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

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

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

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

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

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

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

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

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

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

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


1 Включая обновления для выпуска 1.1 JDK и Java 2 платформы, v1.2, опубликованный в http://java.sun.com.

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

3 UnsupportedClassVersionError, подкласс ClassFormatError, был представлен в Java 2 платформы, v1.2, чтобы включить легкой идентификации a ClassFormatError вызванный попыткой загрузить класс представлял использование неподдерживаемой версии class формат файла.

4 метод runFinalizersOnExit был сначала реализован в выпуске 1.1 JDK, но был осужден в Java 2 платформы, v1.2.

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

Спецификация Виртуальной машины JavaTM
Авторское право © Sun Microsystems, Inc 1999 года. Все права защищены
Пожалуйста, отправьте любые комментарии или исправления к jvm@java.sun.com

free hit counter