Spec-Zone .ru
спецификации, руководства, описания, API
|
Содержание | Предыдущий | Следующий | Индекс | Спецификация Виртуальной машины JavaTM |
ГЛАВА 2
Виртуальная машина Java была разработана, чтобы поддерживать язык программирования Java. Некоторые понятия и словарь с языка Java таким образом необходимы, чтобы понять виртуальную машину. Эта глава дает действительно краткий обзор Java, чтобы поддерживать обсуждение виртуальной машины Java, чтобы следовать. Его материал был сжат из Спецификации языка Java, Джеймсом Гослингом, Биллом Джоем, и Гаем Стилом. Для полного обсуждения языка Java, или для деталей и примеров материала в этой главе, ссылаются на ту книгу. Читатели, знакомые с той книгой, могут хотеть пропустить эту главу. Читатели, знакомые с Java, но не со Спецификацией языка Java, должны, по крайней мере, просмотреть эту главу для терминологии, которую это представляет.
Эта глава не пытается обеспечить введение в или полную обработку языка Java. Для введения в Java см. Язык программирования Java Кеном Арнольдом и Джеймсом Гослингом.
ftp://unicode.org
. В этой информации об обновлении есть несколько незначительных ошибок; сошлитесь на Спецификацию языка Java для исправлений. Обновления к информации о Unicode, опубликованной там, будут отправлены под URL http://java.sun.com/docs/books/index.html
. За исключением комментариев и идентификаторов (§2.2) и содержание символьных и строковых литералов (§2.3), все входные элементы в программе Java формируются из только символов ASCII. ASCII (ANSI X3.4) является Стандартный американский код обмена информацией. Первые 128 символов кодировки символов Unicode являются символами ASCII.
Метод Java Character.isJavaLetter
возвраты true
когда передано символ Unicode, который, как полагают, является буквой в идентификаторах Java. Метод Java Character.isJavaLetterOrDigit
возвраты true
когда передано символ Unicode, который, как полагают, является буквой или цифрой в идентификаторах Java.
Два идентификатора являются тем же самым, только если у них есть тот же самый символ Unicode для каждой буквы или цифры; идентификаторы, у которых есть то же самое внешнее появление, могут все еще отличаться. Идентификатор не должен быть тем же самым как ключевым словом Java или булевым литералом (true or
false
).
String
введите (§2.4.7), или нулевой тип (§2.4). Строковые литералы и, более широко, строки, которые являются значениями константных выражений, "интернируются", чтобы совместно использовать уникальные экземпляры, используя метод String.intern
. У нулевого типа есть одно значение, нулевая ссылка, обозначенная литералом null
.
boolean
у типа есть два значения, обозначенные литералами true
и false
.
Типы языка Java делятся на две категории: типы примитивов (§2.4.1) и ссылочные типы (§2.4.5). Есть также специальный нулевой тип, тип выражения null
, у которого нет никакого имени. Нулевая ссылка является единственным возможным значением выражения нулевого типа, и может всегда преобразовываться в любой ссылочный тип. Практически, программист Java может проигнорировать нулевой тип и только симулировать это null
специальный литерал, который может иметь любой ссылочный тип.
Соответствуя типам примитивов и ссылочным типам, есть две категории значений данных, которые могут быть сохранены в переменных, передали как параметры, возвращенные методами, и работали на: примитивные значения (§2.4.1) и ссылочные значения (§2.4.5).
Типы примитивов boolean
введите и числовые типы. Числовые типы являются целочисленными типами и типами с плавающей точкой.
Целочисленные типы byte
, short
, int
, и long
, чьи значения являются 8-разрядными, 16-разрядными, 32-разрядными, и 64-разрядными two's-дополнительными целыми числами со знаком, соответственно, и char
, чьи значения являются 16-разрядными целыми без знака, представляющими символы Unicode (§2.1).
Типы с плавающей точкой float
, чьи значения являются 32-разрядным IEEE 754 числа с плавающей точкой, и double
, чьи значения являются 64-разрядным IEEE 754 числа с плавающей точкой как определено в Стандарте IEEE для Двоичной Арифметики С плавающей точкой, Стандарт ANSI/IEEE 754-1985 (IEEE, Нью-Йорк). Стандарт IEEE 754 включает не только положительный и числа величины знака минус, но также и положительный, и отрицательный обнуляет, положительные и отрицательные бесконечности, и специальное Не-число (после этого сокращал НЭН), значение. Значение НЭН используется, чтобы представить результат определенных операций, таких как делящийся нуль нулем.
boolean
у типа есть значения истинности true
и false
.
boolean
), арифметические операторы, постепенно увеличьтесь и декрементный, поразрядный логичный и операторы сдвига, и числовой бросок (§2.6.8). Операнды определенных унарных операторов и бинарных операторов подвергаются числовому продвижению (§2.6.9).
Встроенные целочисленные операторы не указывают на переполнение или потерю значимости всегда; они повторяются на переполнении или потере значимости. Единственные целочисленные операторы, которые могут выдать исключение, являются целочисленным дележом и целочисленными операторами остатка, которые могут бросить ArithmeticException
если правый операнд является нулем.
Любое значение любого целочисленного типа может быть брошено к или от любого числового типа. Нет никаких бросков между целочисленными типами и типом boolean
.
boolean
), арифметические операторы, инкремент и декремент, и числовой бросок (§2.6.8). Если по крайней мере один из операндов к бинарному оператору имеет тип с плавающей точкой, то работа является работой с плавающей точкой, даже если другой операнд является неотъемлемой частью. Операнды определенных унарных операторов и бинарных операторов подвергаются числовому продвижению (§2.6.9).
Операторы на числах с плавающей точкой ведут себя точно как определено IEEE 754. В частности Java требует поддержки IEEE 754 денормализованные числа с плавающей точкой и постепенная потеря значимости, которые облегчают доказывать требуемые свойства определенных числовых алгоритмов.
Java требует, чтобы арифметика с плавающей точкой вела себя как будто каждый оператор с плавающей точкой, округленный ее результат с плавающей точкой к точности результата. Неточные результаты должны быть округлены к представимому значению, самому близкому к бесконечно точному результату; если два самых близких представимых значения одинаково рядом, тот с его младшим значащим разрядным нулем выбирается. Это - значение по умолчанию стандарта IEEE 754 округление режима, известного как раунд-к-самому-близкому.
Java использует режим раунда к нулю, преобразовывая значение с плавающей точкой в целое число (§2.6.3). Режим раунда к нулю действует, как если бы число было усеченным, отбрасывая биты мантиссы. Раунд к нулю выбирает как его результат значение формата, самое близкое к и не больше в величине чем бесконечно точный результат.
Java операторы с плавающей точкой не производит исключений (§2.15). Работа, которая переполнения производят бесконечность со знаком; работа, которая потери значимости производят нуль со знаком; и работа, у которой нет никакого математически определенного результата, производит НЭН. Все числовые операции (за исключением числового сравнения) с
НЭН как операнд производит
НЭН в результате.
Любое значение любого типа с плавающей точкой может быть брошено (§2.6.8) к или от любого числового типа. Нет никаких бросков между типами с плавающей точкой и типом boolean
.
boolean
Значения boolean
выражения могут использоваться в операторах управления Java и как первый операнд условного оператора ?:
. Интегральное значение x
может быть преобразован в значение типа boolean
, после соглашения языка C, которое любое ненулевое значение true
, по выражению x!=0
. Ссылка на объект obj
может быть преобразован в значение типа boolean
, после соглашения языка C, что любая ссылка кроме null
true
, по выражению obj!=null
. Между типом нет никаких бросков boolean
и любой другой тип.
Экземпляр класса явно создается выражением создания экземпляра класса, или вызывая newInstance
метод класса Class
. Массив явно создается выражением создания массива. Объект создается в "куче" Java, и собирается "мусор" после того, как нет больше ссылок на это. Объекты никогда не исправляются или освобождаются явными директивами языка Java.
Может быть много ссылок на тот же самый объект. У большинства объектов есть состояние, сохраненное в полях объектов, которые являются экземплярами классов или в переменных, которые являются компонентами объекта массива. Если две переменные содержат ссылки на тот же самый объект, состояние объекта может быть изменено, используя ссылку одной переменной на объект, и затем измененное состояние может наблюдаться через ссылку другой переменной.
У каждого объекта есть связанная блокировка (§2.17, §8.13), который используется synchronized
методы и synchronized
оператор, чтобы обеспечить управление параллельным доступом, чтобы утвердить многократными потоками (§2.17, §8.12).
Ссылочные типы формируют иерархию. Каждый тип класса является подклассом другого типа класса, за исключением класса Object
(§2.4.6), который является суперклассом (§2.8.3) всех других типов классов. Все объекты, включая массивы, поддерживают методы класса Object
. Строковые литералы (§2.3) являются ссылками на экземпляры класса String
(§2.4.7).
Object
Object
суперкласс (§2.8.3) всех других классов. Переменная типа Object
может содержать ссылку на любой объект, является ли это экземпляром класса или массива. Весь класс и типы массива наследовали методы класса Object
. String
String
представьте последовательности символов Unicode (§2.1). A String
у объекта есть постоянное, неизменное значение. Строковые литералы (§2.3) являются ссылками на экземпляры класса String
. instanceof
, и условный оператор ?:
. Совместимость значения переменной с ее типом гарантируется проектом языка Java, потому что значения по умолчанию (§2.5.1) являются совместимыми, и все присвоения на переменную проверяются, во время компиляции, для совместимости присвоения.
static
(§2.9.1) в пределах объявления класса, или с или без ключевого слова static
в интерфейсном объявлении. Переменные класса создаются, когда класс или интерфейс загружаются (§2.16.2) и инициализируются на создании к значениям по умолчанию (§2.5.1). Переменная класса эффективно прекращает существование, когда ее класс или интерфейс разгружаются (§2.16.8) после того, как любое необходимое завершение класса (§2.16.8) было завершено.
static
(§2.9.1). Если у класса T есть поле a, которое является переменной экземпляра, то новая переменная экземпляра создаваемого и инициализированного к значению по умолчанию (§2.5.1) как часть каждого недавно создаваемого объекта класса T или любого класса, который является подклассом T. Переменная экземпляра эффективно прекращает существование, когда, объектом которого это - поле, больше не ссылается, после любого необходимого завершения объекта был завершен (§2.16.7).
catch
пункт a try
оператор (§2.15.2). Новая переменная инициализируется с фактическим объектом, связанным с исключением (§2.15.3). Параметр обработчика исключений эффективно прекращает существование когда выполнение блока, связанного с catch
пункт (§2.15.2) полон.
for
оператор, новая переменная создается для каждой локальной переменной, объявленной в операторе объявления локальной переменной, сразу содержавшем в пределах того блока или for
оператор. Локальная переменная не инициализируется, однако, до оператора объявления локальной переменной, который объявляет, что это выполняется. Локальная переменная эффективно прекращает существование когда выполнение блока или for
оператор полон. byte
, значение по умолчанию является нулем, то есть, значением (byte)0
.
short
, значение по умолчанию является нулем, то есть, значением (short)0
.
int
, значение по умолчанию является нулем, то есть, 0
.
long
, значение по умолчанию является нулем, то есть, 0L
.
float
, значение по умолчанию является положительным нулем, то есть, 0.0f
.
double
, значение по умолчанию является положительным нулем, то есть, 0.0d
.
char
, значение по умолчанию является нулевым символом, то есть, 'u0000'
.
boolean
, значение по умолчанию false
.
null
(§2.3).
newInstance
метод, чтобы произвести объект. Этот класс вызывают классом объекта. Объект, как говорят, является экземпляром своего класса и всех суперклассов его класса. Иногда класс объекта вызывают, его "тип времени выполнения," но "класс" является более точным термином. (Иногда у переменной или выражения, как говорят, есть "тип времени выполнения," но это - злоупотребление терминологией; это обращается к классу объекта, упомянутого значением переменной или выражения во время выполнения, предполагая, что значение не null
. Должным образом разговор, тип является понятием времени компиляции. У переменной или выражения есть тип; объект или массив не имеют никакого типа, но принадлежат классу.)
Тип переменной всегда объявляется, и тип выражения может быть выведен во время компиляции. Тип ограничивает возможные значения, которые может содержать переменная, или выражение может произвести во время выполнения. Если значение времени выполнения является ссылкой, которая не является null
, это обращается к объекту, или выстройте, у которого есть класс (не тип), и тот класс обязательно будет совместимым с типом времени компиляции.
Даже при том, что у переменной или выражения может быть тип времени компиляции, который является интерфейсным типом, нет никаких экземпляров интерфейсов (§2.13). Переменная или выражение, тип которого является интерфейсным типом, могут сослаться на любой объект чьи реализации класса тот интерфейс.
У каждого массива также есть класс. У классов для массивов есть странные имена, которые не являются допустимыми идентификаторами Java; например, класс для массива int
у компонентов есть имя "[I"
.
Числовые продвижения являются преобразованиями, которые изменяют операнд числовой работы к более широкому типу, или оба операнда числовой работы к общему типу, так, чтобы работа могла быть выполнена.
В Java есть шесть широких видов преобразований:
String
(§2.4.7).
+
оператор, когда одним из параметров является a String
; это не будет покрыто далее. byte
к short
, int
, long
, float
, или double
short
к int
, long
, float
, или double
char
к int
, long
, float
, или double
int
к long
, float
, или double
long
к float
или double
float
к double
float
к double
не теряйте информацию вообще; числовое значение сохраняется точно. Преобразование int
или a long
значение к float
, или a long
значение к double
, может потерять точность, то есть, результат может потерять некоторые из младших значащих битов значения; получающееся значение с плавающей точкой является правильно округленной версией целочисленного значения, используя режим раунда-к-самому-близкому IEEE 754 (§2.4.3).
Согласно этому правилу, расширяющееся преобразование целого числа со знаком оценивает целочисленному типу, просто подписываются - расширяет two's-дополнительное представление целочисленного значения, чтобы заполнить более широкий формат. Расширяющееся преобразование значения типа char
к нулю целочисленного типа - расширяет представление символьного значения, чтобы заполнить более широкий формат.
Несмотря на то, что потеря точности может произойти, расширяя преобразования среди типов примитивов никогда не приводит к исключению на этапе выполнения (§2.15).
byte
к char
short
к byte
или char
char
к byte
или short
int
к byte
, short
, или char
long
к byte
, short
, char
, или int
float
к byte
, short
, char
, int
, или long
double
к byte
, short
, char
, int
, long
, или float
int
значение 32763
вводить byte
производит значение -5
). Сужение преобразований может также потерять точность.Сужающееся преобразование целого числа со знаком к целочисленному типу просто отбрасывает все кроме n битов самых низкоуровневых, где n является числом битов, используемых, чтобы представить тип. Это может заставить получающееся значение иметь различный знак чем входное значение.
Сужающееся преобразование символа к целочисленному типу аналогично просто отбрасывает все кроме n самых низких битов, где n является числом битов, используемых, чтобы представить тип. Это может заставить получающееся значение быть отрицательным числом, даже при том, что символы представляют 16-разрядные значения целого без знака.
В сужающемся преобразовании числа с плавающей точкой к целочисленному типу, если число с плавающей точкой НЭН, результат преобразования
0
из соответствующего типа. Если число с плавающей точкой является слишком большим, чтобы быть представленным целочисленным типом, или является положительной бесконечностью, результатом является самое большое представимое значение целочисленного типа. Если число с плавающей точкой является слишком маленьким, чтобы быть представленным, или является отрицательной бесконечностью, результатом является самое маленькое представимое значение целочисленного типа. Иначе, результатом является число с плавающей точкой, округленное к нулю к целочисленному значению, используя режим раунда к нулю IEEE 754 (§2.4.3)
Сужающееся преобразование из double
к float
ведет себя в соответствии с IEEE 754. Результат правильно округляется, используя режим раунда-к-самому-близкому IEEE 754 (§2.4.3). Значение, слишком маленькое, чтобы быть представленным как a float
преобразовывается в положительный или отрицательный нуль; значение, слишком большое, чтобы быть представленным как a float
преобразовывается в положительную или отрицательную бесконечность. A double
НЭН всегда преобразовывается в a
float
НЭН.
Несмотря на то, что переполнение, потеря значимости, или потеря точности могут произойти, сужая преобразования среди типов примитивов никогда не приводит к исключению на этапе выполнения.
Object
к любому другому типу класса.)
final
и не реализует K. (Важный особый случай - то, что есть сужающееся преобразование из типа класса Object
к любому интерфейсному типу.)
Object
к любому типу массива.
Object
к любому интерфейсному типу.
final
.
final
, при условии, что T реализует J.
[]
любому массиву вводят TC[]
, при условии, что SC и TC являются ссылочными типами и есть разрешенное преобразование сужения от SC до TC. ClassCastException
. int
.
byte
, short
, или char
.
Преобразование присвоения никогда не вызывает исключение. Значение типа примитива не должно быть присвоено переменной ссылочного типа. Значение ссылочного типа не должно быть присвоено переменной типа примитива. Значение типа boolean
может быть присвоен только переменной ввести boolean
. Значение нулевого типа может быть присвоено любому ссылочному типу.
Присвоение значения ссылочного типа времени компиляции S (источник) к переменной ссылочного типа времени компиляции T (цель) разрешается:
Object
.
[]
, то есть, массив компонентов SC типа:
Object
.
Cloneable
.
[]
, массив компонентов TC типа, тогда также
Кастинг может преобразовать значение любого числового типа к любому другому числовому типу. Значение типа boolean
не может быть брошен к другому типу. Значение ссылочного типа не может быть брошено к значению типа примитива.
Некоторые броски могут быть доказаны неправильными во время компиляции и результат в ошибке времени компиляции. Иначе, или бросок может быть доказан корректным во время компиляции, или проверка достоверности времени выполнения требуется. (См. Спецификацию языка Java для деталей.), Если значение во время выполнения является нулевой ссылкой, то бросок позволяется. Если проверка в сбоях времени выполнения, a ClassCastException
бросается.
Числовые продвижения используются, чтобы преобразовать операнды числового оператора к общему типу, где работа может быть выполнена. Два вида числового продвижения являются унарным числовым продвижением и двоичным числовым продвижением. Аналогичные преобразования в C вызывают "обычными унарными преобразованиями" и "обычными двоичными преобразованиями." Числовое продвижение не является общей функцией Java, а скорее свойством определенных определений встроенных операторов.
Оператор, который применяет унарное числовое продвижение единственному операнду числового типа, преобразовывает операнд типа byte
, short
, или char
к int
, и иначе оставляет операнд в покое. Операнды операторов сдвига продвигаются, независимо используя унарные числовые продвижения.
Когда оператор применяет двоичное числовое продвижение паре числовых операндов, следующие правила применяются, в порядке, используя расширяющееся преобразование (§2.6.2), чтобы преобразовать операнды по мере необходимости:
double
, другой преобразовывается в double
.
float
, другой преобразовывается в float
.
long
, другой преобразовывается в long
.
int
. Простое имя является единственным идентификатором (§2.2). Полностью определенные имена обеспечивают доступ к элементам пакетов и ссылочных типов. Полностью определенное имя (§2.7.8) состоит из имени, "." маркера, и идентификатора.
Не все идентификаторы в программах Java являются частью имени. Идентификаторы также используются в объявлениях, где идентификатор определяет имя, которым объект будет известен в выражениях доступа к полю и выражениях вызова метода, и в метках оператора и break
и continue
операторы, которые обращаются к меткам оператора.
Каждый узел Java определяет, как пакеты, единицы компиляции, и подпакеты создаются и сохранены; какие высокоуровневые имена пакета находятся в контексте в определенной компиляции; и какие пакеты доступны. Пакеты могут быть сохранены в локальной файловой системе в распределенной файловой системе, или в некоторой форме базы данных.
Имя компонента имени пакета или имя класса могли бы содержать символ, который не может по закону появиться в обычном каталоге файловой системы узла или имени файла: например, символ Unicode на системе, которая позволяет только символы ASCII в именах файлов.
Система Java должна поддерживать по крайней мере один неназванный пакет; это может поддерживать больше чем один неназванный пакет, но не обязано делать так. То, какие единицы компиляции находятся в каждом неназванном пакете, определяется хост-системой. Неназванные пакеты обеспечиваются Java преимущественно для удобства, разрабатывая маленькие или временные приложения или только начиная разработку.
import
объявление позволяет тип, который, как объявляют в другом пакете, был известен простым именем, а не полностью определенным именем (§2.7.9) типа. Объявление импорта влияет только на описания типа единственной единицы компиляции. Единица компиляции автоматически импортирует каждый из public
имена типов объявляются в предопределенном пакете java.lang
.
Вообще, подпакеты пакета определяются хост-системой. Однако, стандартный пакет java
всегда имеет подпакеты lang
, util
, io
, и net
. Ни у каких двух отличных элементов того же самого пакета не может быть того же самого простого имени (§2.7.1), но у элементов различных пакетов может быть то же самое простое имя.
У типа класса может быть два или больше метода с тем же самым простым именем, если у них есть различные числа параметров, или различный параметр вводит по крайней мере одну позицию параметра. Такое имя элемента метода, как говорят, перегружается. Тип класса может содержать объявление для метода с тем же самым именем и той же самой подписью как метод, который был бы иначе наследован от суперкласса или суперинтерфейса. В этом случае метод суперкласса или суперинтерфейса не наследован. Если метод, не наследованный, abstract
, новое объявление, как говорят, реализует это; если это не abstract
, новое объявление, как говорят, переопределяет это.
Object
(§2.4.6), и поле length
, который является константой (final
) поле каждого массива. Java обеспечивает механизмы для того, чтобы они ограничили квалифицированный доступ, предотвратили пользователей пакета или класса от в зависимости от ненужных деталей реализации того пакета или класса. Управление доступом также применяется к конструкторам.
Доступен ли пакет, определяется хост-системой.
Класс или интерфейс могут быть объявлены public
, когда к этому может получить доступ, используя полностью определенное имя, любой код Java, который может получить доступ к пакету, в котором это объявляется. Класс или интерфейс, который не объявляется public
от можно получить доступ, и только от, где угодно в пакете, в котором это объявляется.
Каждое поле или метод интерфейса должны быть public
. Каждый элемент a public
интерфейс неявно public
, действительно ли ключевое слово public
появляется в его объявлении. Если интерфейс не public
, тогда каждые из его полей и методов должны быть явно объявлены public
. Из этого следует, что элемент интерфейса доступен, если и только если сам интерфейс доступен.
Поле, метод, или конструктор класса могут быть объявлены, используя самое большее один из public
, private
, или protected
ключевые слова. A public
к элементу может получить доступ любой код Java. A private
к элементу можно получить доступ только изнутри класса, который содержит его объявление. Элемент, который не объявляется public
, protected
, или private
как говорят, имеет доступ по умолчанию и может быть получен доступ от, и только от, где угодно в пакете, в котором он объявляется.
A protected
к элементу объекта может получить доступ только код, ответственный за реализацию того объекта. Быть точным, a protected
к элементу можно получить доступ отовсюду в пакете, в котором он объявляется и, кроме того, к нему можно получить доступ изнутри любого объявления подкласса типа класса, который содержит его объявление, при условии, что определенным ограничениям повинуются.
boolean
, char
, byte
, short
, int
, long
, float
, или double
.
.
"сопровождаемый простым (элемент) имя подпакета.
.
"сопровождаемый простым именем класса или интерфейса.
[]
". Тело класса объявляет элементы (поля и методы), статические инициализаторы, и конструкторы.
.
Идентификатор. Если класс находится в неназванном пакете, то у класса есть полностью определенный Идентификатор имени. Два класса являются тем же самым классом (и поэтому тот же самый тип), если они загружаются тем же самым загрузчиком класса (§2.16.2), и у них есть то же самое полностью определенное имя (§2.7.9).
public
, как обсуждено в §2.7.8. abstract
класс является классом, который является неполным, или рассмотренный неполным. Только abstract
классы могут иметь abstract
методы (§2.10.3), то есть, методы, которые объявляются, но еще не реализуются.
Класс может быть объявлен final
если его определение полно, и никакие подклассы не требуются или требуются. Поскольку a final
у класса никогда нет подклассов, методов a final
класс не может быть переопределен в подклассе. Класс не может быть обоими final
и abstract
, потому что реализация такого класса никогда не могла завершаться.
Класс объявляется public
сделать его тип доступным для пакетов кроме того, в котором это объявляется. A public
класс доступен от других пакетов, используя или его полностью определенное имя или более короткое имя, создаваемое import
объявление (§2.7.2), всякий раз, когда узел разрешает доступ к своему пакету. Если классу недостает public
модификатор, доступ к объявлению класса ограничивается пакетом, в котором это объявляется.
extends
пункт в объявлении класса определяет прямой суперкласс текущего класса, класса, из реализации которого получается реализация текущего класса. Класс, как говорят, является прямым подклассом класса это extends
. Только класс Object
(у §2.4.6) нет никакого прямого суперкласса. Если extends
пункт опускается от объявления класса, тогда суперкласс нового класса Object
. Отношение подкласса является переходным закрытием прямого отношения подкласса. Класс A является подклассом класса C, если A является прямым подклассом C, или если есть прямой подкласс B C, и класс A является подклассом Б. Класс А, как, говорят, суперкласс класса C всякий раз, когда C является подклассом A.
Object
, у которого нет никакого прямого суперкласса.
private
не наследованы подклассами того класса. Элементы класса, которые не объявляются private
, protected
, или public
не наследованы подклассами, объявленными в пакете кроме того, в котором объявляется класс. Конструкторы (§2.12) и статические инициализаторы (§2.11) не являются элементами и поэтому не наследованы.static
) переменные существуют однажды на класс. Переменные экземпляра существуют однажды на экземпляр класса. Поля могут включать инициализаторы и могут быть изменены, используя различные ключевые слова модификатора. Если класс объявляет поле с определенным именем, то объявление того поля, как говорят, скрывает любого и все доступные объявления полей с тем же самым именем в суперклассах и суперинтерфейсах класса. Класс наследовал от его прямого суперкласса и прямых суперинтерфейсов все поля суперкласса и суперинтерфейсов, которые доступны, чтобы кодировать в классе и не скрываются объявлением в классе. К скрытому полю можно получить доступ при использовании полностью определенного имени (если это static
) или при использовании выражения доступа к полю, которое содержит бросок к супертипу класса или ключевому слову super
.
public
, protected
, или private
, как обсуждено в §2.7.8. Если поле объявляется static
, там существует точно одно воплощение поля, независимо от того сколько экземпляров (возможно нуль) класса может в конечном счете быть создано. A static
поле, иногда называемое переменной класса, воплощается, когда класс инициализируется (§2.16.4).
Поле, которое не объявляется static
вызывается переменной экземпляра. Всякий раз, когда новый экземпляр класса создается, новая переменная, связанная с тем экземпляром, создается для каждой переменной экземпляра, объявленной в том классе или в любом из его суперклассов.
Поле может быть объявлено final
, когда его оператор объявления должен включать переменный инициализатор (§2.9.2). И класс и переменные экземпляра (static
и не -static
поля), может быть объявлен final
. Однажды a final
поле было инициализировано, оно всегда содержит то же самое значение. Если a final
поле содержит ссылку на объект, тогда состояние объекта может быть изменено операциями на объекте, но поле будет всегда обращаться к тому же самому объекту.
Переменные могут быть отмечены transient
указать, что они не часть постоянного состояния объекта. transient
атрибут может использоваться реализацией Java, чтобы поддерживать специальные системные службы. Спецификация языка Java еще не определяет детали таких служб.
Язык Java позволяет потокам что совместно используемые переменные доступа сохранять частные рабочие копии переменных; это позволяет более эффективную реализацию многократных потоков (§2.17). Эти рабочие копии должны быть согласованными с основными копиями в совместно используемой основной памяти только в предписанных точках синхронизации, а именно, когда объекты блокируются или разблокировались (§2.17). Как правило, чтобы гарантировать, что совместно используемые переменные последовательно и достоверно обновляются, поток должен гарантировать, что у него есть эксклюзивный доступ к таким переменным, получая блокировку, которая традиционно осуществляет взаимное исключение для тех совместно используемых переменных.
Java обеспечивает второй механизм, который более удобен в некоторых целях: поле может быть объявлено volatile
, когда поток должен согласовать свою рабочую копию поля с основной копией каждый раз, когда это получает доступ к переменной. Кроме того операции на основных копиях одной или более энергозависимых переменных от имени потока выполняются основной памятью в точно порядке что поток, который требуют. A final
поле не может также быть объявлено volatile
.
static
поле), тогда переменный инициализатор оценивается и присвоение, выполняемое точно однажды, когда класс инициализируется (§2.16.4).
static
), тогда переменный инициализатор оценивается и присвоение, выполняемое каждый раз, когда экземпляр класса создается. super
ключевое слово. public
, protected
, и private
обсуждаются в §2.7.8. abstract
объявление метода представляет метод, поскольку элемент, обеспечивая его подпись (§2.10.2), возвращает тип, и throws
пункт (если кто-либо), но не обеспечивает реализацию. Объявление abstract
метод м. должен появиться в пределах abstract
класс (вызывают это A). Каждый подкласс, который не является самостоятельно abstract
должен обеспечить реализацию для м. Метод объявляется abstract
не может также быть объявлен private
, static
, final
, native
, или synchronized
.
Метод, который объявляется static
вызывается методом класса. Метод класса всегда вызывается независимо от определенного объекта. Метод класса может обратиться к другим полям и методам класса простым именем, только если они - методы класса и класс (static
) переменные.
Метод, который не объявляется static
метод экземпляра. Метод экземпляра всегда вызывается относительно объекта, который становится текущим объектом к который ключевые слова this
и super
отнеситесь во время выполнения тела метода.
Метод может быть объявлен final
препятствовать тому, чтобы подклассы переопределили или скрыли это. A private
метод и все методы объявляются в a final
класс (§2.8.2) неявно final
, потому что невозможно переопределить их. Если метод final
или неявно final
, компилятор или генератор кода времени выполнения могут безопасно "встроить" тело a final
метод, заменяя вызов метода с кодом в его теле.
A synchronized
метод получит блокировку монитора (§2.17) прежде, чем он выполнится. Для класса (static
) метод, блокировка, связанная с объектом класса для класса метода, используется. Для метода экземпляра, блокировка, связанная с this
(объект, для которого вызывается метод) используется. Та же самая блокировка на объект используется synchronized
оператор.
Метод может быть объявлен native
указать, что это реализуется в зависимом от платформы коде, обычно записанном в другом языке программирования, таком как C, C++, или ассемблер.
Статические инициализаторы и инициализаторы переменной класса выполняются в текстовом порядке. Они, возможно, не обращаются к переменным класса, объявленным в классе, объявления которого появляются дословно после использования, даже при том, что эти переменные класса находятся в контексте. Это ограничение разрабатывается, чтобы поймать, во время компиляции, наиболее круговой или иначе уродливые инициализации.
+
, и явными вызовами конструктора от других конструкторов; они никогда не вызываются выражениями вызова метода. Доступом к и наследованием конструкторов управляют модификаторы доступа public
, protected
, и private
(§2.7.8). Объявления конструктора не являются элементами. Они никогда не наследованы и поэтому не подвергаются сокрытию или переопределению.
Если тело конструктора не начинается с явного вызова конструктора, и объявляемый конструктор не является частью исконного класса Object
, тогда тело конструктора, как неявно предполагает компилятор, начинается с вызова конструктора суперкласса"super();
", вызов конструктора его прямого суперкласса, который не берет параметров.
Если класс не объявляет конструкторов, то конструктор по умолчанию, который не берет параметров, автоматически обеспечивается. Если объявляемый класс Object
, тогда у конструктора по умолчанию есть пустое тело. Иначе, конструктор по умолчанию не берет параметров и просто вызывает конструктора суперкласса без параметров. Если класс объявляется public
, тогда конструктору по умолчанию неявно дают модификатор доступа public
. Иначе, конструктору по умолчанию подразумевал доступ по умолчанию никакой модификатор доступа (§2.7.8).
Класс может быть разработан, чтобы предотвратить код вне объявления класса от создания экземпляров класса, объявляя по крайней мере одному конструктору, предотвратить создание неявного конструктора, и объявляя, что все конструкторы private
.
abstract
методы. У этого типа нет никакой реализации, но иначе несвязанные классы могут реализовать его, обеспечивая реализации для abstract
методы. Программы Java могут использовать интерфейсы, чтобы сделать это ненужным для связанных классов, чтобы совместно использовать общее abstract
суперкласс или добавить методы к Object
. Интерфейс, как могут объявлять, является прямым расширением одного или более других интерфейсов, означая, что он неявно определяет весь abstract
методы и константы интерфейсов, которые это расширяет, за исключением любых констант, которые это может скрыть, и возможно добавляющий недавно объявленные собственные элементы.
Класс, как могут объявлять, непосредственно реализует один или более интерфейсов, означая, что любой экземпляр класса реализует весь abstract
методы определяются тем интерфейсом. Класс обязательно реализует все интерфейсы, которые делают его прямые суперклассы и прямые суперинтерфейсы. Это (многократное) интерфейсное наследование позволяет объектам поддерживать (многократные) общие поведения, не совместно используя реализации.
Переменная, чья объявленный типом интерфейсный тип, может иметь как его значение ссылка на объект, который является экземпляром любого класса, который, как объявляют, реализует указанный интерфейс. Не достаточно, что класс, оказывается, реализует весь abstract
методы интерфейса; класс или один из его суперклассов, как должны фактически объявлять, реализуют интерфейс, или иначе класс, как полагают, не реализует интерфейс.
public
и abstract
. Модификатор доступа public
обсуждается в (§2.7.8). Каждый интерфейс неявно abstract
. Все элементы интерфейсов неявно public
. Интерфейс не может быть final
, потому что реализация такого класса никогда не могла завершаться.
extends
пункт обеспечивается, тогда объявляемый интерфейс расширяет каждый из других именованных интерфейсов, и поэтому наследовал методы и константы каждого из других именованных интерфейсов. Любой класс это implements
объявленный интерфейс, как также полагают, реализует все интерфейсы, которые расширяет этот интерфейс и которые доступны для класса. implements
пункт в объявлении класса перечисляет имена интерфейсов, которые являются прямыми суперинтерфейсами объявляемого класса. Все интерфейсы в текущем пакете доступны. Интерфейсы в других пакетах доступны, если хост-система разрешает доступ к пакету, и интерфейс объявляется public
.
Интерфейсный K типа является суперинтерфейсом типа класса C, если K является прямым суперинтерфейсом C; или если у C есть прямой суперинтерфейс J, у которого есть K как суперинтерфейс; или если K является суперинтерфейсом прямого суперкласса C. Класс, как говорят, реализует все свои суперинтерфейсы.
Нет никакого аналога класса Object
для интерфейсов; то есть, в то время как каждый класс является расширением класса Object
, нет никакого единственного интерфейса, которого все интерфейсы являются расширениями.
Интерфейсные элементы являются или полями или методами.
static
и final
. У интерфейсов нет переменных экземпляра. Каждое полевое объявление в интерфейсе самостоятельно неявно public
. Объявление константы в интерфейсе не должно включать ни один из модификаторов transient
или volatile
. У каждого поля в теле интерфейса должно быть выражение инициализации, которое не должно быть константным выражением. Переменный инициализатор оценивается и присвоение, выполняемое точно однажды, когда интерфейс инициализируется (§2.16.4).
abstract
. Каждое объявление метода в теле интерфейса неявно public
. Метод, объявленный в интерфейсе, не должен быть объявлен static
, потому что в Java static
методы не могут быть abstract
. Метод, объявленный в теле интерфейса, не должен быть объявлен native
или synchronized
, потому что те ключевые слова описывают свойства реализации, а не интерфейсные свойства; однако, метод, объявленный в интерфейсе, может быть реализован методом, который объявляется native
или synchronized
в классе, который реализует интерфейс. Метод, объявленный в теле интерфейса, не должен быть объявлен final
; однако, можно быть реализован методом, который объявляется final
в классе, который реализует интерфейс.
Интерфейс наследовал от его прямых суперинтерфейсов все методы суперинтерфейсов, которые не переопределяются объявлением в интерфейсе.
Если у двух методов интерфейса (ли оба объявленные в том же самом интерфейсе, или обоих наследованных интерфейсом, или один объявленный и один наследованный) есть то же самое имя, но различные подписи, то имя метода, как говорят, перегружается.
Object
(§2.4.6). Все методы класса Object
может быть вызван на массив. Объект массива содержит много переменных. То число может быть нулем, когда массив, как говорят, пуст. У переменных, содержавшихся в массиве, нет никаких имен; вместо этого на них ссылаются выражения доступа массива, которые используют неотрицательные целочисленные индексные значения. Эти переменные вызывают компонентами массива. Если у массива есть n компоненты, мы говорим, что n является длиной массива.
Массив нулевых компонентов не является тем же самым как нулевой ссылкой (§2.4).
[]
. Компонентный тип массива может самостоятельно быть типом массива. Компоненты такого массива могут содержать ссылки на подмассивы. Если, запускаясь с какого-либо типа массива, каждый рассматривает его компонентный тип, и затем (если это - также тип массива), компонентный тип того типа, и так далее, в конечном счете нужно достигнуть компонентного типа, который не является типом массива; это вызывают типом элемента исходного массива, и компоненты на этом уровне структуры данных вызывают элементами исходного массива.
Есть одна ситуация, в которой элемент массива может быть массивом: если тип элемента Object
(§2.4.6), тогда некоторые или все элементы могут быть массивами, потому что каждый объект массива может быть присвоен переменной типа Object
.
В Java, в отличие от C, массива char
не a String
(§2.4.6), и ни один a String
ни массив char
завершается 'u0000'
( NUL
Символьный). Java String
объект является неизменным (его значение никогда не изменяется), в то время как массив char
имеет изменчивые элементы.
Тип элемента массива может быть любым типом, или примитивный или ссылочный. В частности массивы с интерфейсным типом как компонентный тип поддерживаются; элементы такого массива могут иметь как их значение нулевая ссылка или экземпляры любого типа класса, который реализует интерфейс. Массивы с abstract
тип класса как компонентный тип поддерживается; элементы такого массива могут иметь как их значение нулевая ссылка или экземпляры любого подкласса этого abstract
класс, который не является самостоятельно abstract
.
Поскольку длина массива не является частью своего типа, единственная переменная типа массива может содержать ссылки на массивы различных длин. Как только объект массива создается, его длина никогда не изменяется. Чтобы заставить переменную типа массив обратиться к массиву различной длины, ссылка на различный массив должна быть присвоена переменной.
Если у переменной типа массив v есть тип A[]
, где A является ссылочным типом, тогда v может содержать ссылку на любой тип B массива[]
, если B может быть присвоен (§2.6.6).
int
значения; short
, byte
, или char
значения могут также использоваться, поскольку они подвергаются унарному числовому продвижению (§2.6.9) и становятся int
значения. Все массивы с 0 источниками. Массив с длиной n может быть индексирован целыми числами 0 через n - 1. Во время выполнения проверяются все доступы массива; попытка использовать индекс, который является меньше чем нуль или больше чем или равный длине массива, вызывает ArrayIndexOutOf-Bounds---Exception
быть брошенным.
Программы Java могут также выдать исключения явно, используя throw
операторы. Это обеспечивает альтернативу старомодному стилю условий ошибки из-за неправильного обращения, возвращая отличенные ошибочные значения, такие как целочисленное значение -1
, где отрицательная величина обычно не ожидалась бы.
Каждое исключение представляется экземпляром класса Throwable
или один из его подклассов; такой объект может использоваться, чтобы перенести информацию от точки, в которой исключение происходит с обработчиком, который ловит это. Обработчики устанавливаются catch
пункты try
операторы. Во время процесса выдачи исключения виртуальная машина Java резко завершает, один за другим, любые выражения, операторы, метод и вызовы конструктора, статические инициализаторы, и полевые выражения инициализации, которые начали, но не завершили выполнение в текущем потоке. Этот процесс продолжается, пока обработчик не находится, который указывает, что это обрабатывает выданное исключение, называя класс исключения или суперкласс класса исключения. Если никакой такой обработчик не находится, то метод uncaught-Exception
вызывается для ThreadGroup
это - родитель текущего потока.
Механизм исключения Java интегрируется с моделью синхронизации Java (§2.17), так, чтобы блокировки были должным образом выпущены как synchronized
операторы и вызовы synchronized
методы завершаются резко.
Определенные исключения, покрытые этим разделом, - то, что подмножество предопределенных исключений, которые могут быть выданы непосредственно работой виртуальной машины Java. Дополнительные исключения могут быть выданы пользовательским кодом или библиотекой классов; эти исключения не покрываются здесь. См. Спецификацию языка Java для информации обо всех предопределенных исключениях.
throw
оператор выполнялся в коде Java.
stop
из класса Thread
был вызван, или
Throwable
и экземпляры его подклассов. Эти классы являются, все вместе, классами исключений.catch
пункт a try
оператор, который обрабатывает исключение. Оператор или выражение динамически включаются a catch
пункт, если это появляется в пределах try
блок try
оператор которого catch
пункт является частью, или если вызывающая сторона оператора или выражения динамически включается catch
пункт.
Вызывающая сторона оператора или выражения зависит от того, где это происходит:
new-Instance
это выполнялось, чтобы заставить объект создаваться.
static
переменная, тогда вызывающая сторона является выражением, которое использовало класс или интерфейс, чтобы заставить это быть инициализированным. catch
дескрипторы пункта исключение определяется, сравнивая класс объекта, который был брошен в объявленный тип параметра catch
пункт. catch
пункт обрабатывает исключение, если тип его параметра является классом исключения или суперклассом класса исключения. Эквивалентно, a catch
пункт поймает любой объект исключения, который является instanceof
объявленный тип параметра.
Передача управления, которая происходит, когда исключение выдается причины резкое завершение выражений и операторов до a catch
с пунктом встречаются, который может обработать исключение; выполнение тогда продолжается, выполняя блок этого catch
пункт. Код, который вызвал исключение, никогда не возобновляется.
Если нет catch
пункт, обрабатывающий исключение, может быть найден, тогда текущий поток (поток, который встречался, исключение) завершается, но только в конце концов finally
пункты были выполнены и метод uncaughtException
был вызван для ThreadGroup
это - родитель текущего потока.
В ситуациях, где это является требуемым, чтобы гарантировать, что один блок кода всегда выполняется за другим, даже если тот другой блок кода завершается резко, a try
оператор с a finally
пункт может использоваться. Если a try
или catch
блок в a try-finally
или try-catch-finally
оператор завершается резко, тогда finally
пункт выполняется во время распространения исключения, даже если никакое соответствие catch
пункт в конечном счете находится. Если a finally
пункт выполняется из-за резкого завершения a try
блок и finally
сам пункт завершается резко, тогда причина резкого завершения try
блок отбрасывается, и новая причина резкого завершения распространяется оттуда.
Большинство исключений в Java происходит синхронно в результате действия потоком, в котором они происходят, и в точке в программе Java, которая определяется, чтобы возможно привести к такому исключению. Асинхронное исключение является, в отличие от этого, исключением, которое может потенциально произойти в любой точке в выполнении программы Java.
Асинхронные исключения редки в Java. Они происходят только в результате:
stop
методы могут быть вызваны одним потоком, чтобы влиять на другой поток или все потоки в указанной группе потока. Они являются асинхронными, потому что они могут произойти в любой точке в выполнении другого потока или потоков. InternalError
считается асинхронным так, чтобы это могло быть обработано, используя тот же самый механизм, который обрабатывает stop
метод, как будет теперь описан. Java разрешает небольшому, но ограниченному количеству выполнения происходить прежде, чем асинхронное исключение будет выдано. Этой задержке разрешают позволить оптимизированному коду обнаруживать и выдавать эти исключения в точках, где это практично, чтобы обработать их, повинуясь семантике языка Java.
Простая реализация могла бы опросить относительно асинхронных исключений в точке каждой инструкции передачи управления. Так как у программы Java есть конечный размер, это обеспечивает привязанный полная задержка обнаружения асинхронного исключения. Так как никакое асинхронное исключение не произойдет между передачами управления, у генератора кода есть некоторая гибкость, чтобы переупорядочить вычисление между передачами управления для большей производительности.
Все исключения в Java точны: когда передача управления имеет место, все эффекты выполняемых операторов и выражения, оцененные перед, точка, от которой выдается исключение, должно казаться, имела место. Никакие выражения, операторы, или части этого, которые происходят после точки, от которой выдается исключение, может казаться, не были оценены. Если оптимизированный код теоретически выполнил некоторые из выражений или операторов, которые следуют за точкой, в которой происходит исключение, такой код должен быть подготовлен скрыть это спекулятивное выполнение от видимого пользователем состояния программы Java.
Throwable
, прямой подкласс Object
. Классы Exception
и Error
прямые подклассы Throwable
. Класс RuntimeException
прямой подкласс Exception
. Программы Java могут использовать существующие ранее классы исключений в throw
операторы, или определяют дополнительные классы исключений, как подклассы Throwable
или любого из его подклассов, как соответствующий. Чтобы использовать в своих интересах время компиляции Java, проверяя на обработчики исключений, это типично, чтобы определить самые новые классы исключений как проверенные классы исключений, определенно как подклассы Exception
это не подклассы RuntimeException
.
Exception
и RuntimeException
Exception
суперкласс всех стандартных исключений, с которых обычные программы могут хотеть восстановиться. Класс RuntimeException
подкласс класса Exception
. Подклассы RuntimeException
классы исключений непроверенные. Пакет java.lang
определяет следующие стандартные исключения на этапе выполнения непроверенные:
ArithmeticException
: Исключительная арифметическая ситуация возникла, такие как целочисленное деление или работа остатка с делителем нуля.
ArrayStoreException
: Попытка была предпринята, чтобы сохранить в компонент массива значение, класс которого не является присвоением, совместимым с компонентным типом массива.
ClassCastException
: Попытка была предпринята, чтобы бросить ссылку на объект к несоответствующему типу.
IllegalMonitorStateException
: Поток попытался ожидать на или уведомить другие потоки, ожидающие относительно объекта, что он не заблокировал.
IndexOutOfBoundsException
: Или индекс некоторого вида (такой относительно массива, строки, или вектор) или поддиапазон, определенный или двумя индексными значениями или индексом и длиной, испытывал недостаток диапазона.
NegativeArraySizeException
: Попытка была предпринята, чтобы создать массив с отрицательной длиной.
NullPointerException
: Попытка была предпринята, чтобы использовать нулевую ссылку в случае, где ссылка на объект требовалась.
SecurityException
: Нарушение защиты было обнаружено. Error
и его стандартные подклассы являются исключениями, с которых обычные программы, как обычно ожидают, не восстановятся. Класс Error
отдельный подкласс Throwable
, отличный от Exception
в иерархии классов, чтобы позволить программам использовать идиому
} catch (Exception e) {
поймать все исключения, от которых восстановление может быть возможным, не фиксируя ошибки, от которых восстановление обычно не возможно. Пакет java.lang
определяет все ошибочные классы, описанные здесь. Виртуальная машина Java бросает объект, который является экземпляром подкласса LinkageError
когда загрузка (§2.16.2), соединяясь (§2.16.3), или инициализация (§2.16.4) ошибка происходит:
ClassFormatError
, ClassCircularityError
, и NoClassDefFoundError
описываются там.
IncompatibleClassChangeError
), а именно, IllegalAccessError
, Instantiation-Error
, NoSuchFieldError
, и NoSuchMethodError
, описываются там.
VerifyError
описывается там.
AbstractMethodError
.
ExceptionInInitializerError
если выполнение статического инициализатора или инициализатора для a static
поле (§2.11) приводит к исключению, которое не является Error
или подкласс Error
. VirtualMachineError
когда внутреннее ограничение ошибки или ресурса препятствует тому, чтобы это реализовало семантику Языка Java. Эта спецификация определяет следующие ошибки виртуальной машины:
InternalError
: Внутренняя ошибка произошла в виртуальной машине Java, из-за отказа в программном обеспечении, реализовывая виртуальную машину, отказ в базовом программном обеспечении хост-системы, или отказ в аппаратных средствах. Эта ошибка поставляется асинхронно, когда она обнаруживается и может произойти в любой точке в программе Java.
OutOfMemoryError
: Виртуальная машина Java исчерпала или виртуальную память или физическую память, и автоматический менеджер по хранению был неспособен исправить достаточно памяти, чтобы удовлетворить объектный запрос создания.
StackOverflowError
: Виртуальная машина Java исчерпала стековое пространство для потока, обычно потому что поток делает неограниченное число рекурсивных вызовов в результате отказа в программе выполнения.
UnknownError
: Исключение или ошибка произошли, но, по некоторым причинам, виртуальная машина Java неспособна сообщить о фактическом исключении или ошибке. main
из некоторого указанного класса, передавая это единственный параметр, который является массивом строк. Это заставляет указанный класс быть загруженным (§2.16.2), соединялся (§2.16.3) с другими типами, которые это использует, и инициализированный (§2.16.4). Метод main
должен быть объявлен public
, static
, и void
. Способ, которым начальный класс определяется к виртуальной машине Java, выходит за рамки этой спецификации, но это типично в средах узла, которые используют командные строки для полностью определенного имени класса, который будет определен как параметр командной строки и для последующих параметров командной строки, которые будут использоваться в качестве строк, которые будут обеспечены как параметр методу main
. Например, в реализации JDK Sun на UNIX, командной строке
java Terminator Hasta la vista Baby!
запустит виртуальную машину Java, вызывая метод main
из класса Terminator
(класс в неназванном пакете), передавая это массив, содержащий четыре строки "Hasta"
, "la"
, "vista"
, и "Baby!"
. Мы теперь обрисовываем в общих чертах шаги, которые виртуальная машина может сделать, чтобы выполниться Terminator
, как пример загрузки, соединения, и процессов инициализации, которые описываются далее в более поздних разделах.
Начальная попытка выполнить метод main
из класса Terminator
обнаруживает что класс Terminator
не загружается - то есть, виртуальная машина в настоящий момент не содержит двоичное представление для этого класса. Виртуальная машина тогда использует a ClassLoader
(§2.16.2), чтобы попытаться найти такое двоичное представление. Если этот процесс перестал работать, ошибка бросается. Этот процесс загрузки описывается далее в (§2.16.2).
После Terminator
загружается, это должно быть инициализировано прежде main
может быть вызван, и тип (класс или интерфейс) должен всегда соединяться прежде, чем это будет инициализировано. Соединение включает проверку, подготовку, и (дополнительно) разрешение. Соединение описывается далее в §2.16.3.
Проверка проверяет что загруженное представление Terminator
хорошо формируется, с надлежащей таблицей символов. Проверка также проверяет, что код, который реализует Terminator
повинуется семантическим требованиям виртуальной машины Java. Если проблема обнаруживается во время проверки, ошибка бросается. Проверка описывается далее в §2.16.3.
Подготовка включает выделение статического хранения и любых структур данных, которые используются внутренне виртуальной машиной, такой как таблицы метода. Если проблема обнаруживается во время подготовки, ошибка бросается. Подготовка описывается далее в §2.16.3.
Разрешение является процессом проверки символьных ссылок от Terminator
к другим классам и интерфейсам, загружая другие классы и интерфейсы, которые упоминаются и проверяя, что ссылки корректны.
Шаг разрешения является дополнительным во время начального редактирования. Реализация может разрешить символьную ссылку от класса или интерфейса, который соединяется очень рано, даже на грани разрешения всех символьных ссылок от классов и интерфейсов, на которые далее ссылаются, рекурсивно. (Это разрешение может привести к ошибкам от дальнейшей загрузки и соединения шагов.) Этот выбор реализации представляет одно экстремальное значение и подобен виду статического редактирования, которое было сделано много лет в простых реализациях языка C.
Реализация может вместо этого хотеть разрешать символьную ссылку только, когда она активно используется; непротиворечивое использование этой стратегии всех символьных ссылок представило бы "самую ленивую" форму разрешения. В этом случае, если Terminator
имел несколько символьных ссылок на другой класс, ссылки не могли бы быть разрешены один во время возможно нисколько, если бы эти ссылки никогда не использовались во время выполнения программы.
Единственное требование к тому, когда разрешение выполняется, - то, что любые ошибки, обнаруженные во время разрешения, должны быть брошены в точку в программе, где некоторые меры предпринимаются программой, которая могла бы, прямо или косвенно, потребовать редактирования к классу или интерфейсу, включенному в ошибку. В "статическом" выборе реализации в качестве примера, описанном ранее, загружаясь и соединяя ошибки, мог произойти прежде, чем программа выполняется, если они включили класс или интерфейс, упомянутый в классе Terminator
или любой из далее, классы, на которые рекурсивно ссылаются, и интерфейсы. В системе, которая реализовывала "самое ленивое" разрешение, эти ошибки будут брошены только, когда символьная ссылка будет активно использоваться.
Процесс разрешения описывается далее в §2.16.3.
В нашем рабочем примере виртуальная машина все еще пытается выполнить метод, основной из класса Terminator
. Это - предпринятое активное использование (§2.16.4) класса, который разрешается, только если класс был инициализирован.
Инициализация состоит из выполнения любых инициализаторов переменной класса и статических инициализаторов класса Terminator
, в текстовом порядке. Но прежде Terminator
может быть инициализирован, его прямой суперкласс должен быть инициализирован, так же как прямой суперкласс его прямого суперкласса, и так далее, рекурсивно. В самом простом случае, Terminator
имеет Object
как его неявный прямой суперкласс; если класс Object
еще не был инициализирован, тогда это должно быть инициализировано прежде Terminator
инициализируется.
Если класс Terminator
имеет другой класс Super
как его суперкласс, тогда Super
должен быть инициализирован прежде Terminator
. Это требует загрузки, проверки, и подготовки Super,
если это не было уже сделано, и, в зависимости от реализации, может также включить разрешение символьных ссылок от Super
и так далее, рекурсивно.
Инициализация может таким образом вызвать загрузку, соединение, и ошибки инициализации, включая такие ошибки, включая другие типы.
Процесс инициализации описывается далее в §2.16.4.
Наконец, после завершения инициализации для класса Terminator
(во время которого другая последовательная загрузка, соединение, и инициализация, возможно, произошли), метод main
из Terminator
вызывается.
Class
объект представить класс или интерфейс. Двоичный формат класса или интерфейса обычно class
формат файла (см. Главу 4, "Формат файла класса"). Процесс загрузки реализуется классом ClassLoader
и его подклассы. Различные подклассы ClassLoader
может реализовать различные политики загрузки. В частности загрузчик класса может кэшировать двоичные представления классов и интерфейсов, выбрать их с упреждением основанный на ожидаемом использовании, или загрузить группу связанных классов вместе. Эти действия, возможно, не абсолютно прозрачны к рабочему приложению Java, если, например, недавно скомпилированная версия класса не находится, потому что более старая версия кэшируется загрузчиком класса. Это - ответственность загрузчика класса, однако, чтобы отразить загружающиеся ошибки только в точках в программе, где они, возможно, возникли, не выбирая с упреждением или групповая загрузка.
Если ошибка происходит во время загрузки класса, то экземпляр одного из следующих подклассов класса LinkageError
будет брошен в любую точку в программе Java, которая (прямо или косвенно) использует тип:
ClassCircularityError
: Класс или интерфейс не могли быть загружены, потому что это будет свой собственный суперкласс или суперинтерфейс (§2.13.2).
ClassFormatError
: Двоичные данные, который подразумевает определять требуемый скомпилированный класс или интерфейс, уродливы.
NoClassDefFoundError
: Никакое определение для требуемого класса или интерфейса не могло быть найдено соответствующим загрузчиком класса. Java позволяет гибкость реализации относительно того, когда соединение действий (и, из-за рекурсии, загрузка) имеют место, при условии, что семантику языка уважают, что класс или интерфейс полностью проверяются и готовятся прежде, чем это будет инициализировано, и что ошибки, обнаруженные во время редактирования, бросаются в точку в программе, где некоторые меры предпринимаются программой, которая могла бы потребовать редактирования к классу или интерфейсу, включенному в ошибку.
Например, реализация может хотеть разрешать каждую символьную ссылку в классе или взаимодействовать через интерфейс индивидуально, только когда это используется (ленивое или последнее разрешение), или разрешить их внезапно, например, в то время как класс проверяется (статическое разрешение). Это означает, что процесс разрешения может продолжаться в некоторых реализациях, после того, как класс или интерфейс был инициализирован.
Проверка гарантирует, что двоичное представление класса или интерфейса структурно корректно. Например, это проверяет, что у каждой инструкции есть допустимый код работы; то, что каждая команда перехода переходит к запуску некоторой другой инструкции, а не в середину инструкции; то, что каждому методу предоставляют структурно корректную подпись; и что каждая инструкция повинуется дисциплине типа языка Java.
Если ошибка происходит во время проверки, то экземпляр следующего подкласса класса LinkageError
будет брошен в точку в программе Java, которая заставила класс быть проверенным:
VerifyError
: Двоичное определение для класса или интерфейса, отказавшего, чтобы передать ряд необходимых проверок, чтобы проверить, что это повинуется семантике языка Java и что это не может нарушить целостность виртуальной машины Java. Реализации Java должны обнаружить следующую ошибку во время подготовки:
AbstractMethodError
: Класс, который, как объявляют, не является abstract
имеет abstract
метод. Это может произойти, например, если метод, который является первоначально нет abstract
изменяется, чтобы быть abstract
после другого класса, который наследовался теперь -abstract
объявление метода было скомпилировано. Двоичный файл Java ссылается на другие классы и интерфейсы и их поля, методы, и конструкторов символически, используя полностью определенные имена (§2.7.9) других классов и интерфейсов. Для полей и методов эти символьные ссылки включают имя класса или интерфейсного типа, который объявляет поле или метод, так же как имя поля или метода непосредственно, вместе с соответствующей информацией о типе.
Прежде, чем символьная ссылка может использоваться, она должна подвергнуться разрешению, в чем символьная ссылка проверяется, чтобы быть корректной и, обычно, заменяется прямой ссылкой, которая может быть более эффективно обработана, если ссылка неоднократно используется.
Если ошибка происходит во время разрешения, то экземпляр одного из следующих подклассов класса IncompatibleClassChangeError
, или некоторого другого подкласса, или IncompatibleClassChangeError
непосредственно (который является подклассом класса Linkage-Error
) может быть брошен в любую точку в программе Java, которая использует символьную ссылку на тип:
IllegalAccessError
: С символьной ссылкой встретились, который определяет использование или присвоение поля, или вызов метода, или создание экземпляра класса, к которому у кода, содержащего ссылку, нет доступа, потому что поле или метод были объявлены private
, protected
, или доступ по умолчанию (нет public
), или потому что класс не был объявлен public
. Это может произойти, например, если поле, которое первоначально объявляется public
изменяется, чтобы быть private
после того, как другой класс, который обращается к полю, был скомпилирован.
InstantiationError
: С символьной ссылкой встретились, который используется в выражении создания экземпляра класса, но экземпляр не может быть создан, потому что ссылка, оказывается, обращается к интерфейсу или к abstract
класс. Это может произойти, например, если класс, который является первоначально нет abstract
изменяется, чтобы быть abstract
после того, как другой класс, который обращается к рассматриваемому классу, был скомпилирован.
NoSuchFieldError
: С символьной ссылкой встретились, который обращается к определенному полю определенного класса или интерфейса, но класс или интерфейс не объявляют поле того имени (определенно не достаточно для этого просто быть наследованным полем того класса или интерфейса). Это может произойти, например, если полевое объявление было удалено из класса после другого класса, который обращается к полю, был скомпилирован.
NoSuchMethodError
: С символьной ссылкой встретились, который обращается к определенному методу определенного класса или интерфейса, но класс или интерфейс не объявляют метод того имени и подписи (определенно не достаточно для этого просто быть наследованным методом того класса или интерфейса). Это может произойти, например, если объявление метода было удалено из класса после другого класса, который обращается к методу, был скомпилирован Прежде, чем класс инициализируется, его суперкласс должен быть инициализирован, но интерфейсы, реализованные классом, не должны быть инициализированы. Точно так же суперинтерфейсы интерфейсной потребности не быть инициализированными перед интерфейсом инициализируются.
Класс или интерфейсный тип T будут инициализированы при его первом активном использовании, которое происходит если:
final
и static
, и это инициализируется со значением константного выражения времени компиляции. Java определяет, что ссылка на такое поле должна быть разрешена во время компиляции к копии постоянной величины времени компиляции, таким образом, использование такого поля никогда не является активным использованием. Намерение здесь состоит в том, что у типа есть ряд инициализаторов, которые помещают это в непротиворечивое состояние, и что это состояние является первым состоянием, которое наблюдается другими классами. Статические инициализаторы и инициализаторы переменной класса выполняются в текстовом порядке и, возможно, не обращаются к переменным класса, объявленным в классе, объявления которого появляются дословно после использования, даже при том, что эти переменные класса находятся в контексте. Это ограничение разрабатывается, чтобы обнаружить, во время компиляции, наиболее круговой или иначе уродливые инициализации.
Прежде, чем класс инициализируется, его суперклассы инициализируются, если они не были ранее инициализированы.
Ссылка на поле является активным использованием только класса, или взаимодействуйте через интерфейс, это фактически объявляет это, даже при том, что это могло бы быть упомянуто через имя подкласса, подынтерфейса, или класса, который реализует интерфейс.
Инициализация интерфейса не делает, себя, требует инициализации любого из ее суперинтерфейсов.
Class
объект был уже проверен и подготовлен, и что Class
объект содержит состояние, которое может указывать на одну из четырех ситуаций: Class
объект проверяется и готовится, но не инициализируется.
Class
объект инициализируется некоторым определенным потоком T.
Class
объект полностью инициализируется и готов к употреблению.
Class
объект находится в ошибочном состоянии, возможно потому что шаг проверки или подготовки, отказавший, или потому что инициализация была предпринята и отказавшей. Class
объект, который представляет класс или интерфейс, который будет инициализирован. Это включает ожидание, пока текущий поток не может получить блокировку для того объекта (§8.13).
wait
на этом Class
объект (который временно выпускает блокировку). Когда текущий поток просыпается от wait
, повторите этот шаг.
Class
возразите и полный обычно.
Class
возразите и полный обычно.
Class
объект находится в ошибочном состоянии, тогда инициализация не возможна. Выпустите блокировку на Class
объект и бросок a NoClassDefFoundError
.
Class
объект теперь происходит текущим потоком, и выпустите блокировку на Class
объект.
Class
объект представляет класс, а не интерфейс, и суперкласс этого класса еще не был инициализирован, тогда рекурсивно выполните эту всю процедуру для суперкласса. В случае необходимости проверьте и подготовьте суперкласс сначала. Если инициализация суперкласса завершается резко из-за выданного исключения, то заблокируйте это Class
объект, маркируйте это ошибочным, уведомьте все потоки ожидания, выпустите блокировку, и завершитесь резко, выдавая то же самое исключение, которое следовало из инициализации суперкласса.
final
static
переменные и поля интерфейсов, значения которых являются константами времени компиляции, инициализируются сначала.
Class
объект, маркируйте, он полностью инициализировал, уведомьте все потоки ожидания, выпустите блокировку, и обычно завершайте эту процедуру.
Error
или один из его подклассов, затем создайте новый экземпляр класса ExceptionInInitializerError
, с E как параметр, и использование этот объект вместо E в следующем шаге. Но если новый экземпляр ExceptionInInitializerError
не может быть создан потому что OutOfMemoryError
происходит, тогда вместо этого используйте OutOfMemoryError
объект вместо E в следующем шаге.
Class
объект, маркируйте это ошибочным, уведомьте все потоки ожидания, выпустите блокировку, и завершите эту процедуру резко с причиной E или ее заменой как определено в предыдущем шаге. ExceptionInInitializerError
как описано здесь. newInstance
метод класса Class
создает новый экземпляр класса, представленного Class
объект, для которого был вызван метод. String
литерал может создать новое String
объект (§2.4.7), чтобы представить тот литерал. Это, возможно, не происходит если то же самое String
был ранее интернирован.
String
объект представить результат. Операторы конкатенации строк могут также создать временные объекты обертки для значения типа примитива (§2.4.1). Всякий раз, когда новый экземпляр класса создается, место в памяти выделяется для него с комнатой для всех переменных экземпляра, объявленных в типе класса и всех переменных экземпляра, объявленных в каждом суперклассе типа класса, включая все переменные экземпляра, которые могут быть скрыты. Если нет достаточного пространства, доступного, чтобы выделить память для объекта, то создание экземпляра класса завершается резко с OutOfMemoryError
. Иначе, все переменные экземпляра в новом объекте, включая объявленных в суперклассах, инициализируются к их значениям по умолчанию (§2.5.1). Непосредственно перед тем, как ссылка на недавно создаваемый объект возвращается как результат, обозначенный конструктор обрабатывается, чтобы инициализировать новый объект, используя следующую процедуру:
this
), затем оцените параметры и обработайте тот вызов конструктора, рекурсивно используя эти те же самые пять шагов. Если тот вызов конструктора завершается резко, то эта процедура завершается резко по той же самой причине. Иначе, продолжайте с шагом 5.
this
). Если этот конструктор для класса кроме Object
, тогда этот конструктор начнет с явного или неявного вызова конструктора суперкласса (использование super
). Оцените параметры и обработайте тот вызов конструктора суперкласса, рекурсивно используя эти те же самые пять шагов. Если тот вызов конструктора завершается резко, то эта процедура завершается резко по той же самой причине. Иначе, продолжайте с шагом 4.
Object
имеет a protected
метод вызывают finalize
; этот метод может быть переопределен другими классами. Определенное определение finalize
это может быть вызвано для объекта, вызывается финализатором того объекта. Прежде, чем хранение для объекта исправляется сборщиком "мусора", виртуальная машина Java вызовет финализатор того объекта. Финализаторы обеспечивают шанс освободить ресурсы (такие как дескрипторы файлов или контексты графики операционной системы), который не может быть освобожден автоматически автоматическим менеджером по хранению. В таких ситуациях, просто исправляя память, используемую объектом, не гарантировал бы, что ресурсы, которые она содержала, будут исправлены.
Язык Java не определяет, как скоро финализатор будет вызван, кроме сказать, что это произойдет прежде, чем хранение для объекта снова используется. Кроме того, язык Java не определяет, какой поток вызовет финализатор для любого данного объекта. Если непойманное исключение выдается во время завершения, исключение игнорируется, и завершение того объекта завершается.
finalize
метод объявляется в классе Object
не предпринимает мер. Однако, факт тот класс Object
объявляет a finalize
метод означает что finalize
метод для любого класса может всегда вызывать finalize
метод для его суперкласса, который является обычно хорошей практикой. (В отличие от конструкторов, финализаторы автоматически не вызывают финализатор для суперкласса; такой вызов должен быть кодирован явно.)
Для эффективности реализация может отследить классы, которые не переопределяют finalize
метод класса Object
, или переопределите это тривиальным способом, такой как
protected void finalize() { super.finalize(); }Мы поощряем реализации обрабатывать такие объекты как наличие финализатора, который не переопределяется, и завершить их более эффективно.
finalize
метод может быть вызван явно, точно так же как любой другой метод. Однако, выполнение так не имеет никакого эффекта на возможное автоматическое завершение объекта.
Виртуальная машина Java не налагает упорядочивания на finalize
вызовы метода. Финализаторы можно вызвать в любом порядке, или даже одновременно.
Как пример, если циркулярная соединенная группа незавершенных объектов становится недостижимой, то все объекты могут стать finalizable вместе. В конечном счете финализаторы для этих объектов могут быть вызваны в любом порядке, или даже одновременно использовании многократных потоков. Если автоматический менеджер по хранению позже находит, что объекты недостижимы, то их хранение может быть исправлено.
Класс не может быть разгружен, в то время как любой экземпляр его все еще достижим. Класс или интерфейс не могут быть разгружены в то время как Class
объект, который представляет это, все еще достижим.
Если класс объявляет метод класса classFinalize
это не берет параметров, и не возвращает результата:
static void classFinalize() { . . . }тогда этот метод будет вызван прежде, чем класс разгружается. Как
finalize
метод для объектов, этот метод будет автоматически вызван только однажды. Этот метод может дополнительно быть объявлен private
, protected
, или public
. exit
метод класса Runtime
или класс System
и работа выхода разрешается менеджером безопасности. runFinalizersOnExit
из класса System
с параметром true
.3 Значение по умолчанию не должно выполнить финализаторы на выходе, и это поведение может быть восстановлено, вызывая runFinalizersOnExit
с параметром false
. Вызов runFinalizersOnExit
метод разрешается, только если вызывающей стороне позволяют exit
, и иначе отклоняется менеджером безопасности. Любой поток может быть отмечен как поток демона. Когда код, работающий в некотором потоке, создает новое Thread
объект, тот новый поток первоначально отмечается как поток демона, если и только если поток создания является потоком демона. Программа может измениться, является ли определенный поток потоком демона, вызывая -setDaemon
метод в классе Thread
. Виртуальная машина Java первоначально запускает с единственным потоком недемона, который обычно вызывает метод main
из некоторого класса. Виртуальная машина может также создать другие потоки демона во внутренних целях. Виртуальная машина Java выходит, когда все потоки недемона умерли (§2.16.9).
Java поддерживает кодирование программ, которые, хотя параллельный, все еще показывают детерминированное поведение, обеспечивая механизмы для того, чтобы они синхронизировали параллельное действие потоков. Чтобы синхронизировать потоки, Java использует мониторы, которые являются высокоуровневым механизмом для того, чтобы позволить только одному потоку за один раз выполнять область кода, защищенного монитором. Поведение мониторов объясняется с точки зрения блокировок. Есть блокировка, связанная с каждым объектом.
synchronized
оператор выполняет два специальных действия, относящиеся только к многопоточной работе:
synchronized
; такой метод ведет себя, как будто его тело содержалось в a synchronized
оператор. wait
, notify
, и notifyAll
из класса Object
поддерживайте эффективную передачу управления от одного потока до другого. Вместо того, чтобы просто "вращаться" (неоднократно блокировка и разблокирование объекта видеть, изменилось ли некоторое внутреннее состояние), который использует вычислительное усилие, поток может приостановить себя использование wait
до тех пор, пока другой поток пробуждает это использование notify
или notifyAll
. Это является особенно соответствующим в ситуациях, где у потоков есть отношение производителя-потребителя (активно сотрудничающий на общей цели), а не отношение взаимного исключения (пытающийся избежать конфликтов, совместно используя общий ресурс).Поскольку поток выполняет код, он выполняет последовательность действий. Поток может использовать значение переменной или присвоить его новое значение. (Другие действия включают арифметические операции, условные тесты, и вызовы метода, но они не включают переменные непосредственно.), Если два или больше параллельных действия потоков на совместно используемой переменной, есть возможность, что действия на переменной приведут к зависимым от синхронизации результатам. Эта зависимость от синхронизации свойственна от параллельного программирования и производит одно из немногих мест в Java, где результат программы не определяется исключительно Спецификацией языка Java.
У каждого потока есть рабочая память, в которой он может сохранить копии значений переменных от основной памяти, которые совместно используются всеми потоками. Чтобы получить доступ к совместно используемой переменной, поток обычно сначала получает блокировку и сбрасывает ее рабочую память. Это гарантирует, что совместно использованные значения будут после того загружены от совместно используемой основной памяти до рабочей памяти потока. Разблокировав блокировку, поток гарантирует, что значения, сохраненные потоком в его рабочей памяти, будут записаны обратно к основной памяти.
Взаимодействие потоков с основной памятью, и таким образом друг с другом, может быть объяснено с точки зрения определенных низкоуровневых действий. Есть правила о порядке, в котором могут произойти эти действия. Эти правила налагают ограничения на любую реализацию Java, и программист Java может положиться на правила предсказать возможные поведения параллельной программы Java. Правила действительно, однако, преднамеренно дают конструктору определенные свободы. Намерение состоит в том, чтобы разрешить аппаратные и программные методы определенного стандарта, которые могут значительно улучшить скорость и эффективность параллельного кода.
Кратко помещенный, важными последствиями правил является следующее:
long
и double
значения; см. §8.4.)
2 завершения Класса и разгрузка не реализуются с выпуска 1.0.2 JDK Sun.
3 метод runFinalizersOnExit
не реализуется в выпуске 1.0.2 JDK Sun.
Содержание | Предыдущий | Следующий | Индекс
Спецификация Виртуальной машины Java
Авторское право © 1996, 1997 Sun Microsystems, Inc. Все права защищены
Пожалуйста, отправьте любые комментарии или исправления к jvm@java.sun.com