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


ГЛАВА 6

Имена


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

Имена в программах или просты, состоя из единственного идентификатора, или квалифицированный, состоя из последовательности идентификаторов, разделенных"."маркеры (§6.2).

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

У пакетов и ссылочных типов (то есть, типы классов, интерфейсные типы, и типы массива) есть элементы (§6.4). Элемент может быть отнесен в использование полностью определенного имени N.x, где N является простым или полностью определенным именем, и x является идентификатором. Если N называет пакет, то x является элементом того пакета, который является или классом или интерфейсным типом или подпакетом. Если N называет ссылочный тип или переменную ссылочного типа, то x называет элемент того типа, который является или классом, интерфейсом, полем, или методом.

В определении значения имени (§6.5), контекст возникновения используется, чтобы снять неоднозначность среди пакетов, типов, переменных, и методов с тем же самым именем.

Управление доступом (§6.6) может быть определено в классе, интерфейсе, методе, или полевом объявлении, чтобы управлять, когда доступ к элементу предоставляется. Доступ является различным понятием от контекста; доступ определяет часть текста программы, в пределах которого объявленный объект может быть упомянут полностью определенным именем, выражение доступа к полю (§15.11), или выражение вызова метода (§15.12), в котором метод не определяется простым именем. Доступ по умолчанию - то, что к элементу можно получить доступ где угодно в пределах пакета, который содержит его объявление; другие возможности public, protected, и private.

Полностью определенные и канонические имена (§6.7) и соглашения о присвоении имен (§6.8) также обсуждаются в этой главе.

Имя поля, параметра, или локальной переменной может использоваться в качестве выражения (§15.14.2). Имя метода может появиться в выражении только как часть выражения вызова метода (§15.12). Имя класса или интерфейсного типа может появиться в выражении только как часть литерала класса (§15.8.2), квалифицированный это выражение (§15.8.4), выражение создания экземпляра класса (§15.9), выражение создания массива (§15.10), выражение броска (§15.16), instanceof выражение (§15.20.2), перечислимая константа (§8.9), или как часть полностью определенного имени для поля или метода. Имя пакета может появиться в выражении только как часть полностью определенного имени для класса или соединить интерфейсом с типом.

6.1 Объявления

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

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

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

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

Есть две формы имен: простые имена и полностью определенные имена. Простое имя является единственным идентификатором. Полностью определенное имя состоит из имени,"."маркер, и идентификатор.

В определении значения имени (§6.5), принимается во внимание контекст, в котором появляется имя. Правила §6.5 различают среди контекстов, где имя должно обозначить (обратитесь к), пакет (§6.5.3), тип (§6.5.5), переменная или значение в выражении (§6.5.6), или метод (§6.5.7).

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

В примере:

class Test {
        public static void main(String[] args) {
                Class c = System.out.getClass();
                System.out.println(c.toString().length() +
                                args[0].length() + args.length);
        }
}
идентификаторы Test, main, и первые возникновения args и c не имена; скорее они используются в объявлениях, чтобы определить имена объявленных объектов. Имена String, Class, System.out.getClass, System.out.println, c.toString, args, и args.length появитесь в примере. Первое возникновение length не имя, а скорее идентификатор, появляющийся в выражении вызова метода (§15.12). Второе возникновение length не имя, а скорее идентификатор, появляющийся в выражении вызова метода (§15.12).

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

class TestString {
        char[] value;
        int offset, count;
        int indexOf(TestString str, int fromIndex) {
                char[] v1 = value, v2 = str.value;
                int max = offset + (count - str.count);
                int start = offset + ((fromIndex < 0) ? 0 : fromIndex);
        i:
                for (int i = start; i <= max; i++)
                {
                        int n = str.count, j = i, k = str.offset;
                        while (n-- != 0) {
                                if (v1[j++] != v2[k++])
                                        continue i;
                        } 
                        return i - offset;
                }
                return -1;
        }
}
Этот код был взят от версии класса String и его метод indexOf, где метку первоначально вызвали test. Изменение метки, чтобы иметь то же самое имя как локальная переменная i не затеняет (§6.3.2) метку в пределах объявления i. Идентификатор max возможно, также использовался в качестве метки оператора; метка не затенила бы локальную переменную max в пределах помеченного оператора.

6.3 Контекст Объявления

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

Правила обзора данных для различных конструкций даются в разделах, которые описывают те конструкции. Для удобства правила повторяются здесь:

Контекст объявления заметного (§7.4.3) высокоуровневого пакета является всеми заметными единицами компиляции (§7.3). Объявление пакета, который не заметен, никогда не находится в контексте. Объявления подпакета никогда не находятся в контексте.

Контекст типа, импортированного объявлением единственного импорта типа (§7.5.1) или объявлением "импорт типа по требованию" (§7.5.2), является всем классом и интерфейсными описаниями типа (§7.6) в единице компиляции, в которой появляется объявление импорта.

Контекст элемента, импортированного объявлением единственного статического импорта (§7.5.3) или объявлением "статический импорт по требованию" (§7.5.4), является всем классом и интерфейсными описаниями типа (§7.6) в единице компиляции, в которой появляется объявление импорта.

Контекст высокоуровневого типа является всеми описаниями типа в пакете, в котором объявляется высокоуровневый тип.

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

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

Контекст параметра метода (§8.4.1) или конструктор (§8.8.1) является всем телом метода или конструктора.

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

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

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

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

Контекст локального класса, сразу включенного блоком (§14.2), является остальной частью сразу блока включения, включая его собственное объявление класса. Контекст локального класса, сразу включенного в группе оператора блока переключателя (§14.11), является остальной частью сразу группы оператора блока переключателя включения, включая ее собственное объявление класса.

Контекст локальной переменной объявляется в forInit части основного for оператор (§14.14) включает все следующее:

Контекст локальной переменной объявляется в части FormalParameter улучшенного for оператором (§14.14) является содержавший Оператор

Контекст параметра обработчика исключений, который объявляется в a catch пункт a try оператор (§14.20) является всем блоком, связанным с catch.

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

В примере:

package points;
class Point {
        int x, y;
        PointList list;
        Point next;
}
class PointList {
        Point first;
}

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

6.3.1 Объявления затенения

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

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

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

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

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

Объявление d единственного импорта типа в единице компиляции c пакета p, который импортирует тип, названный n тенями объявления:

всюду по c.

Объявление d единственного статического импорта в единице компиляции c пакета p, который импортирует поле, названное n тенями объявление любого статического поля, названного n, импортированным объявлением "статический импорт по требованию" в c, всюду по c.

Объявление d единственного статического импорта в единице компиляции c пакета p, который импортирует метод, названный n с тенями подписи s объявление любого статического метода, названного n с подписью s, импортированной объявлением "статический импорт по требованию" в c, всюду по c.

Объявление d единственного статического импорта в единице компиляции c пакета p, который импортирует тип, названный n тенями объявления:

всюду по c.

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

Объявление "статический импорт по требованию" никогда не заставляет никакое другое объявление быть затененным.

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

Отметьте, что затенение отлично от сокрытия (§8.3, §8.4.8.2, §8.5, §9.3, §9.5). Сокрытие, в техническом смысле, определенном в этой спецификации, применяется только к элементам, которые были бы иначе наследованы, но являются не из-за объявления в подклассе. Затенение также отлично от затемнения (§6.3.2).

Вот пример затенения полевого объявления объявлением локальной переменной:

class Test {
        static int x = 1;
        public static void main(String[] args) {
                int x = 0;
                System.out.print("x=" + x);
                System.out.println(", Test.x=" + Test.x);
        }
}
производит вывод:

x=0, Test.x=1
Этот пример объявляет:

Так как контекст переменной класса включает все тело класса (§8.2) переменная класса x обычно было бы доступно всюду по всему телу метода main. В этом примере, однако, переменной класса x затенено в пределах тела метода main объявлением локальной переменной x.

Локальная переменная имеет как ее остальная часть контекста блока, в котором она объявляется (§14.4.2); в этом случае это - остальная часть тела main метод, а именно, его инициализатор"0"и вызовы print и println.

Это означает что:

Следующий пример иллюстрирует затенение одного описания типа другим:

import java.util.*;
class Vector {
        int val[] = { 1 , 2 };

}

class Test { public static void main(String[] args) { Vector v = new Vector(); System.out.println(v.val[0]); } }
компиляции и печатные издания:

1
использование класса Vector объявленный здесь в предпочтении к универсальному (§8.1.2) классу java.util.Vector это могло бы быть импортировано по требованию.

6.3.2 Затененные Объявления

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

Затемнение отлично от затенения (§6.3.1) и скрывающийся (§8.3, §8.4.8.2, §8.5, §9.3, §9.5). Соглашения о присвоении имен §6.8 помогают уменьшить затемнение.

6.4 Элементы и Наследование

У пакетов и ссылочных типов есть элементы.

Этот раздел обеспечивает краткий обзор элементов пакетов и ссылочных типов здесь как фон для обсуждения полностью определенных имен и определения значения имен. Для полного описания членства см. §4.4, §4.5.2, §4.8, §4.9, §7.1, §8.2, §9.2, и §10.7.

6.4.1 Элементы Переменных Типа, Параметризованных Типов, Необработанных Типов и Перекрестных Типов

Элементы переменной типа были определены в §4.4, элементы параметризованного вводят §4.5.2, таковые из сырых данных вводят §4.8, и элементы перекрестного типа были определены в §4.9.

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

Элементы пакета (§7) определяются в §7.1. Для удобства мы повторяем что спецификация здесь:

Элементы пакета являются его подпакетами и всем верхним уровнем (§7.6) типы классов (§8) и высокоуровневые типы интерфейса (§9) объявленный во всех единицах компиляции (§7.3) пакета.

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

Например, возможно объявить пакет:

package vector;
public class Vector { Object[] vec; }
это имеет как элемент a public класс называют Vector, даже при том, что пакет java.util также объявляет названный класс Vector. Эти два типов классов отличаются, отражаются фактом, что у них есть различные полностью определенные имена (§6.7). Полностью определенное имя этого примера Vector vector.Vector, тогда как java.util.Vector полностью определенное имя Vector класс обычно включается в платформу Java. Поскольку пакет vector содержит названный класс Vector, этому нельзя было также назвать подпакет Vector.

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

Элементы типа класса (§8.2) являются классами (§8.5, §9.5), интерфейсы (§8.5, §9.5), поля (§8.3, §9.3, §10.7), и методы (§8.4, §9.4). Элементы или объявлены в типе, или наследованы, потому что они - доступные элементы суперкласса или суперинтерфейса, которые не являются ни частными, ни не скрываются, ни переопределенные (§8.4.8).

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

Конструкторы (§8.8) и переменные типа (§4.4) не являются элементами.

Нет никакого ограничения против поля и метода типа класса, имеющего то же самое простое имя. Аналогично, нет никакого ограничения против задействованного класса или задействованного интерфейса типа класса, имеющего то же самое простое имя как поле или метод того типа класса.

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

В примере:

interface Colors {
        int WHITE = 0, BLACK = 1;
}

interface Separates {
        int CYAN = 0, MAGENTA = 1, YELLOW = 2, BLACK = 3;
}

class Test implements Colors, Separates {
        public static void main(String[] args) {
                System.out.println(BLACK); // compile-time error: ambiguous
        }
}
имя BLACK в методе main неоднозначно, потому что класс Test имеет два названные элемента BLACK, один наследованный от Colors и один от Separates.

У типа класса может быть два или больше метода с тем же самым простым именем, если у методов есть подписи, которые не эквивалентны переопределению (§8.4.2). Такое имя элемента метода, как говорят, перегружается.

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

В примере:

class Point {
        float x, y;
        void move(int dx, int dy) { x += dx; y += dy; }
        void move(float dx, float dy) { x += dx; y += dy; }
        public String toString() { return "("+x+","+y+")"; }
}
класс Point имеет два элемента, которые являются методами с тем же самым именем, move. Перегруженный move метод класса Point выбранный для любого определенного вызова метода определяется во время компиляции перегружающейся процедурой разрешения, данной в §15.12.

В этом примере, элементах класса Point float переменные экземпляра x и y объявленный в Point, эти объявленные два move методы, объявленный toString метод, и элементы это Point наследовался от его неявного прямого суперкласса Object (§4.3.2), такой как метод hashCode. Отметьте это Point не наследовался toString метод класса Object потому что тот метод переопределяется объявлением toString метод в классе Point.

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

Элементы интерфейсного типа (§9.2) могут быть классами (§8.5, §9.5), интерфейсы (§8.5, §9.5), поля (§8.3, §9.3, §10.7), и методы (§8.4, §9.4). Элементы интерфейса:

Введите переменные (§4.4), не элементы.

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

В примере:

interface Colors {
        int WHITE = 0, BLACK = 1;
}
interface Separates {
        int CYAN = 0, MAGENTA = 1, YELLOW = 2, BLACK = 3;
}
interface ColorsAndSeparates extends Colors, Separates {
        int DEFAULT = BLACK;                                                                    // compile-time error: ambiguous
}
элементы интерфейса ColorsAndSeparates включайте те элементы, наследованные от Colors и наследованные от Separates, а именно, WHITE, BLACK (сначала два), CYAN, MAGENTA, YELLOW, и BLACK (второй из два). Имя элемента BLACK неоднозначно в интерфейсе ColorsAndSeparates.

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

Элементы типа массива определяются в §10.7. Для удобства мы повторяем ту спецификацию здесь.

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

Пример:

class Test {
        public static void main(String[] args) {
                int[] ia = new int[3];
                int[] ib = new int[6];
                System.out.println(ia.getClass() == ib.getClass());
                System.out.println("ia has length=" + ia.length);
        }
}
производит вывод:

true
ia has length=3
Этот пример использует метод getClass унаследованный от класса Object и поле length. Результат сравнения Class объекты в первом println демонстрирует, что все массивы, компоненты которых имеют тип int экземпляры того же самого типа массива, который является int[].

6.5 Определение Значения Имени

Значение имени зависит от контекста, в котором оно используется. Определение значения имени требует трех шагов. Во-первых, контекст заставляет имя синтаксически попадать в одну из шести категорий: PackageName, TypeName, ExpressionName, MethodName, PackageOrTypeName, или AmbiguousName. Во-вторых, имя, которое первоначально классифицируется его контекстом как AmbiguousName или как PackageOrTypeName, тогда повторно классифицируется, чтобы быть PackageName, TypeName, или ExpressionName. В-третьих, получающаяся категория тогда диктует заключительное определение значения имени (или ошибка компиляции, если у имени нет никакого значения).


PackageName:
        Identifier
        PackageName . Identifier

TypeName:
        Identifier
        PackageOrTypeName . Identifier

ExpressionName:
        Identifier
        AmbiguousName . Identifier

MethodName:
        Identifier
        AmbiguousName . Identifier

PackageOrTypeName:
        Identifier
        PackageOrTypeName . Identifier

AmbiguousName:
        Identifier
        AmbiguousName . Identifier
        

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

6.5.1 Синтаксическая Классификация Имени Согласно Контексту

Имя синтаксически классифицируется как PackageName в этих контекстах:

Имя синтаксически классифицируется как TypeName в этих контекстах:

Имя синтаксически классифицируется как ExpressionName в этих контекстах:

Имя синтаксически классифицируется как MethodName в этих контекстах:

Имя синтаксически классифицируется как PackageOrTypeName в этих контекстах:

Имя синтаксически классифицируется как AmbiguousName в этих контекстах:

6.5.2 Переклассификация Контекстуально Неоднозначных Имен

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

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

package org.rpgpoet;
import java.util.Random;
interface Music { Random[] wizards = new Random[4]; }
и затем рассмотрите этот пример кода в другом пакете:

package bazola;
class Gabriel {
        static int n = org.rpgpoet.Music.wizards.length;
}
Прежде всего, имя org.rpgpoet.Music.wizards.length классифицируется как ExpressionName, потому что он функционирует как PostfixExpression. Поэтому, каждое из имен:

org.rpgpoet.Music.wizards
org.rpgpoet.Music
org.rpgpoet
org 
первоначально классифицируется как AmbiguousName. Они тогда повторно классифицируются:

6.5.3 Значение Имен Пакета

Значение имени, классифицированного как PackageName, определяется следующим образом.

6.5.3.1 Простые Имена Пакета

Если имя пакета состоит из единственного Идентификатора, то этот идентификатор обозначает высокоуровневый пакет, названный тем идентификатором. Если никакой высокоуровневый пакет того имени не находится в контексте (§7.4.4), то ошибка времени компиляции происходит.

6.5.3.2 Квалифицированные Имена Пакета

Если имя пакета имеет форму Q.Идентификатор, тогда Q должен также быть именем пакета. Имя Q пакета.Идентификатор называет пакет, который является элементом под названием Идентификатор в пределах пакета, названного Q. Если Q не называет заметный пакет (§7.4.3), или Идентификатор не является простым именем заметный подпакет того пакета, то ошибка времени компиляции происходит.

6.5.4 Значение PackageOrTypeNames

6.5.4.1 Простой PackageOrTypeNames

Если PackageOrTypeName, Q, происходит в пределах типа под названием KQ, то PackageOrTypeName повторно классифицируется как TypeName.

Иначе, PackageOrTypeName повторно классифицируется как PackageName. Значение PackageOrTypeName является значением повторно классифицированного имени.

6.5.4.2 Квалифицированный PackageOrTypeNames

Учитывая квалифицированный PackageOrTypeName формы Q.Id, если у типа или пакета, обозначенного Q, есть тип элемента под названием Идентификатор, то квалифицированное имя PackageOrTypeName повторно классифицируется как TypeName.

Иначе, это повторно классифицируется как PackageName. Значение квалифицированного PackageOrTypeName является значением повторно классифицированного имени.

6.5.5 Значение Имен типов

Значение имени, классифицированного как TypeName, определяется следующим образом.

6.5.5.1 Простые Имена типов

Если имя типа состоит из единственного Идентификатора, то идентификатор должен произойти в пределах точно одного видимого объявления типа с этим именем, или ошибка времени компиляции происходит. Значение имени типа является тем типом.

6.5.5.2 Квалифицированные Имена типов

Если имя типа имеет форму Q.Идентификатор, тогда Q должен быть или именем типа или именем пакета. Если Идентификатор называет точно один тип, который является элементом типа или пакета, обозначенного Q, то квалифицированное имя типа обозначает тот тип. Если Идентификатор не называет тип элемента (§8.5, §9.5) в пределах Q, или тип элемента под названием Идентификатор в пределах Q не доступен (§6.6), или Идентификатор называет больше чем один тип элемента в пределах Q, то ошибка времени компиляции происходит.

Пример:

package wnj.test;
class Test {
        public static void main(String[] args) {
                java.util.Date date =
                        new java.util.Date(System.currentTimeMillis());
                System.out.println(date.toLocaleString());
        }
}
произведенный следующий вывод в первый раз это было выполнено:

Sun Jan 21 22:56:29 1996
В этом примере имя java.util.Date должен обозначить тип, таким образом, мы сначала используем процедуру рекурсивно, чтобы определить если java.util доступный тип или пакет, который это, и затем надейтесь видеть если тип Date доступно в этом пакете.


Обсуждение

Имена типов отличны от спецификаторов описания типа (§4.3). Имя типа всегда квалифицируется meas другого имени типа. В некоторых случаях необходимо получить доступ к внутреннему классу, который является элементом параметризованного типа:

class GenericOuter<T extends Number> {
        public class Inner<S extends Comparable<S>> {
                        T getT() { return null;}
                        S getS() { return null;}
        }
};

GenericOuter<Integer>.Inner<Double> x1 = null;
Integer i = x1.getT();
Double d = x1.getS();
Если мы получили доступ Inner квалифицируя это с именем типа, как в:

GenericOuter.Inner x2 = null;
мы вызвали бы его использование в качестве необработанного типа, теряя информацию о типе.


6.5.6 Значение Имен Выражения

Значение имени, классифицированного как ExpressionName, определяется следующим образом.

6.5.6.1 Простые Имена Выражения

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

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

Если поле является переменной экземпляра (§8.3), имя выражения должно появиться в пределах объявления метода экземпляра (§8.4), конструктор (§8.8), инициализатор экземпляра (§8.6), или инициализатор переменной экземпляра (§8.3.2.2). Если это появляется в пределах a static метод (§8.4.3.2), статический инициализатор (§8.7), или инициализатор для a static переменная (§8.3.2.1, §12.4.2), затем ошибка времени компиляции происходит.

Тип имени выражения является объявленным типом поля, локальной переменной или параметра после преобразования получения (§5.1.10).

В примере:

class Test {
        static int v;
        static final int f = 3;
        public static void main(String[] args) {
                int i;
                i = 1;
                v = 2;
                f = 33;                         // compile-time error
                System.out.println(i + " " + v + " " + f);
        }
}
имена, используемые в качестве левых сторон в присвоениях на i, v, и f обозначьте локальную переменную i, поле v, и значение f (не переменная f, потому что f a final переменная). Пример поэтому производит ошибку во время компиляции, потому что у последнего присвоения нет переменной как ее левой стороны. Если ошибочное присвоение удаляется, измененный код может быть скомпилирован, и это произведет вывод:

1 2 3

6.5.6.2 Квалифицированные Имена Выражения

Если имя выражения имеет форму Q.Идентификатор, тогда Q был уже классифицирован как имя пакета, имя типа, или имя выражения:

Пример:

class Point {
        int x, y;
        static int nPoints;
}
class Test {
        public static void main(String[] args) {
                int i = 0;
                i.x++;                  // compile-time error
                Point p = new Point();
                p.nPoints();            // compile-time error
        }
}
встречается с двумя ошибками времени компиляции, потому что int переменная i не имеет никаких элементов, и потому что nPoints не метод класса Point.


Обсуждение

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

class Foo<T> {
        public static int classVar = 42;
}
Foo<String>.classVar = 91; // illegal
Вместо этого пишет каждый

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


6.5.7 Значение Имен методов

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

6.5.7.1 Простые Имена методов

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

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

См. §15.12 для дальнейшего обсуждения интерпретации простых имен методов в выражениях вызова метода.

6.5.7.2 Квалифицированные Имена методов

Квалифицированное имя метода может только появиться в контексте выражения вызова метода. Если имя метода имеет форму Q.Идентификатор, тогда Q был уже классифицирован как имя пакета, имя типа, или имя выражения. Если Q является именем пакета, то ошибка времени компиляции происходит. Иначе, Айдахо является именем метода, которое будет использоваться для вызова метода. Если Q является именем типа, то Идентификатор должен назвать по крайней мере один static метод типа Q. Если Q является именем выражения, то T, которым позволяют, являются типом выражения Q; Идентификатор должен назвать по крайней мере один метод типа T. См. §15.12 для дальнейшего обсуждения интерпретации квалифицированных имен методов в выражениях вызова метода.


Обсуждение

Как имена выражения, имена методов могут быть квалифицированы именами типов, но не типами вообще. Импликации подобны тем для имен выражения как обсуждено в §6.5.6.2.


6.6 Управление доступом

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

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

Управление доступом применяется к квалифицированному доступу и к вызову конструкторов по выражениям создания экземпляра класса (§15.9) и явным вызовам конструктора (§8.8.7.1). Доступность также наследование эффектов элементов класса (§8.2), включая сокрытие и метод, переопределяющий (§8.4.8.1).

6.6.1 Определение Доступности

6.6.2 Детали о защищенном доступе

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

6.6.2.1 Доступ к защищенному Элементу

Позвольте C быть классом в который a protected элемент м. объявляется. Доступ разрешается только в пределах тела подкласса S C. Кроме того, если Идентификатор обозначает поле экземпляра или метод экземпляра, то:

6.6.2.2 Квалифицированный Доступ к защищенному Конструктору

Позвольте C быть классом в который a protected конструктор объявляется и позволяется S быть самым внутренним классом в чей объявлении использование protected конструктор происходит. Затем:

6.6.3 Пример Управления доступом

Для примеров управления доступом рассмотрите эти две единицы компиляции:

package points;
class PointVec { Point[] vec; }
и:

package points;
public class Point {
        protected int x, y;
        public void move(int dx, int dy) { x += dx; y += dy; }
        public int getX() { return x; }
        public int getY() { return y; }
}
которые объявляют два типов классов в пакете points:

См. §6.6.7 для примера как protected модификатор доступа ограничивает доступ.

6.6.4 Пример: Доступ к общедоступным и Непубличным Классам

Если классу недостает public модификатор, доступ к объявлению класса ограничивается пакетом, в котором это объявляется (§6.6). В примере:

package points;
public class Point {
        public int x, y;
        public void move(int dx, int dy) { x += dx; y += dy; }

}

class PointList { Point next, prev; }
два класса объявляются в единице компиляции. Класс Point доступно вне пакета points, в то время как класс PointList доступно для доступа только в пределах пакета.

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

package pointsUser;
class Test {
        public static void main(String[] args) {
                points.Point p = new points.Point();
                System.out.println(p.x + " " + p.y);
        }
}
или при использовании объявления единственного импорта типа (§7.5.1), который упоминает полностью определенное имя, так, чтобы простое имя могло использоваться после того:

package pointsUser;
import points.Point;
class Test {
        public static void main(String[] args) {
                Point p = new Point();
                System.out.println(p.x + " " + p.y);
        }}
Однако, эта единица компиляции не может использовать или импортировать points.PointList, который не объявляется public и поэтому недоступный внешний пакет points.

6.6.5 Пример: Поля доступа по умолчанию, Методы, и Конструкторы

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

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

Например, если мы имеем:

package points;
public class Point {
        public int x, y;
        void move(int dx, int dy) { x += dx; y += dy; }
        public void moveAlso(int dx, int dy) { move(dx, dy); }
}
тогда подкласс в другом пакете может объявить несвязанное move метод, с той же самой подписью (§8.4.2) и тип возврата. Поскольку оригинал move метод не доступен от пакета morepoints, super возможно, не используется:

package morepoints;
public class PlusPoint extends points.Point {
        public void move(int dx, int dy) {
                super.move(dx, dy);                                                             // compile-time error
                moveAlso(dx, dy);
        }
}
Поскольку перемещение Point не переопределяется move в PlusPoint, метод moveAlso в Point никогда не призывает перемещение метода PlusPoint.

Таким образом, если Вы удаляете super.move вызовите от PlusPoint и выполните тестовую программу:

import points.Point;
import morepoints.PlusPoint;
class Test {
    public static void main(String[] args) {
        PlusPoint pp = new PlusPoint();
        pp.move(1, 1);

}

}
это обычно завершается. Если перемещение Point были переопределены move в PlusPoint, тогда эта программа рекурсивно вызвала бы бесконечно, до a StackoverflowError произошедший.

6.6.6 Пример: общедоступные Поля, Методы, и Конструкторы

A public элемент класса или конструктор доступны всюду по пакету, где это объявляется и от любого другого пакета, обеспечило пакет, в котором это объявляется, заметно (§7.4.3). Например, в единице компиляции:

package points;
public class Point {
        int x, y;
        public void move(int dx, int dy) {
                x += dx; y += dy;
                moves++;
        }
        public static int moves = 0;
}
public класс Point имеет как public элементы move метод и moves поле. Они public элементы доступны для любого другого пакета, у которого есть доступ к пакету points. Поля x и y не public и поэтому доступны только изнутри пакета points.

6.6.7 Пример: защищенные Поля, Методы, и Конструкторы

Рассмотрите этот пример, где points пакет объявляет:

package points;
public class Point {
        protected int x, y;
        void warp(threePoint.Point3d a) {
                if (a.z > 0)         // compile-time error: cannot access a.z
                        a.delta(this);
        }
}
и threePoint пакет объявляет:

package threePoint;
import points.Point;
public class Point3d extends Point {
        protected int z;
        public void delta(Point p) {
                p.x += this.x;          // compile-time error: cannot access p.x
                p.y += this.y;          // compile-time error: cannot access p.y

        }
        public void delta3d(Point3d q) {
                q.x += this.x;
                q.y += this.y;
                q.z += this.z;
        }
}
который определяет класс Point3d. Ошибка времени компиляции происходит в методе delta здесь: это не может получить доступ к защищенным элементам x и y из его параметра p, потому что, в то время как Point3d (то класс, в который ссылки на поля x и y происходите), подкласс Point (то класс, в который x и y объявляются), это не включается в реализацию a Point (тип параметра p). Метод delta3d может получить доступ к защищенным элементам его параметра q, потому что класс Point3d подкласс Point и включается в реализацию a Point3d.

Метод delta мог попытаться бросить (§5.5, §15.16) его параметр, чтобы быть a Point3d, но этот бросок перестал бы работать, вызывая исключение, если класс p во время выполнения не были Point3d.

Ошибка времени компиляции также происходит в деформации метода: это не может получить доступ к защищенному элементу z из его параметра a, потому что, в то время как класс Point (то класс, в который ссылка на поле z происходит), включается в реализацию a Point3d (тип параметра a), это не подкласс Point3d (то класс, в который z объявляется).

6.6.8 Пример: частные Поля, Методы, и Конструкторы

A private элемент класса или конструктор доступны только в пределах тела высокоуровневого класса (§7.6), который включает объявление элемента или конструктора. Это не наследовано подклассами. В примере:

class Point {
        Point() { setMasterID(); }
        int x, y;
        private int ID;
        private static int masterID = 0;
        private void setMasterID() { ID = masterID++; }
}
private элементы ID, м.asterID, и setMasterID может использоваться только в пределах тела класса Point. К ним не могут получить доступ полностью определенные имена, выражения доступа к полю, или выражения вызова метода вне тела объявления Point.

См. §8.8.8 для примера, который использует a private конструктор.

6.7 Полностью определенные Имена и Канонические имена

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

Примеры:

В примере:

package points;
class Point { int x, y; }
class PointVec {
        Point[] vec;
}
полностью определенное имя типа Point "points.Point"; полностью определенное имя типа PointVec "points.PointVec"; и полностью определенное имя типа поля vec из класса PointVec "points.Point[]".

У каждого пакета, высокоуровневого класса, высокоуровневого интерфейса, и типа примитива есть каноническое имя. У типа массива есть каноническое имя, если и только если у его типа элемента есть каноническое имя. Задействованный класс или элемент взаимодействуют через интерфейс, у М. объявленного в другом классе C есть каноническое имя, если и только если у C есть каноническое имя. В этом случае каноническое имя М. состоит из канонического имени C, сопровождаемого ". ", сопровождаемый простым именем М. Для каждого пакета, высокоуровневого класса, высокоуровневого интерфейса и типа примитива, каноническое имя является тем же самым как полностью определенным именем. Каноническое имя типа массива определяется только, когда у компонентного типа массива есть каноническое имя. В этом случае каноническое имя типа массива состоит из канонического имени компонентного типа типа массива, сопровождаемого"[]".

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

package p;
class O1 { class I{}}
class O2 extends O1{};

В этом примере оба p.O1.I и p.O2.I полностью определяются имена, которые обозначают тот же самый класс, но только p.O1.I его каноническое имя.

6.8 Соглашения о присвоении имен

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

Мы рекомендуем эти соглашения для использования во всех программах, записанных в языке программирования Java. Однако, эти соглашения не должны сопровождаться по-рабски если долго сохранено стандартное использование, диктует иначе. Так, например, sin и cos методы класса java.lang.Math имейте математически стандартные имена, даже при том, что эти имена методов презирают соглашение, предложенное здесь, потому что они коротки и не являются глаголами.

6.8.1 Имена пакета

Имена пакетов, которые должны быть сделаны широко доступными, должны быть сформированы как описано в §7.7. Такие имена всегда являются полностью определенными именами, первый идентификатор которых состоит из двух или трех строчных букв, которые называют Интернет-домен, такой как com, edu, gov, mil, net, org, или двухбуквенный код страны ISO такой как uk или jp. Вот примеры гипотетических уникальных имен, которые могли бы быть сформированы в соответствии с этим соглашением:

com.JavaSoft.jag.Oak
org.npr.pledge.driver
uk.ac.city.rugby.game

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

Когда имена пакета происходят в выражениях:

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

6.8.2 Класс и Интерфейсные Имена типов

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

ClassLoader
SecurityManager
Thread
Dictionary
BufferedInputStream

Аналогично, имена интерфейсных типов должны быть короткими и дескриптивными, не чрезмерно долго, в смешанном случае с первой буквой каждого использованного для своей выгоды слова. Имя может быть дескриптивным существительным или именной группой, которая является соответствующей, когда интерфейс используется, как будто это был абстрактный суперкласс, такой как интерфейсы java.io.DataInput и java.io.DataOutput; или это может быть прилагательное, описывающее поведение, что касается интерфейсов Runnable и Cloneable.

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

6.8.3 Введите Имена переменной

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


Обсуждение

Это облегчает отличать формальные параметры типа от обычных классов и интерфейсов.


Контейнерные типы должны использовать имя E для их типа элемента. Карты должны использовать K для типа их ключей и V для типа их значений. Имя X должен использоваться для произвольных типов исключения. Мы используем T для типа, всякий раз, когда нет ничего более определенного о типе, чтобы отличить это.


Обсуждение

Это часто имеет место в универсальных методах.


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


Обсуждение

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



Обсуждение

Эти соглашения иллюстрируются во фрагментах кода ниже:

public class HashSet<E> extends AbstractSet<E> { ... }
public class HashMap<K,V> extends AbstractMap<K,V> { ... }
public class ThreadLocal<T> { ... }
public interface Functor<T, X extends Throwable> {
    T eval() throws X;
}


Когда параметры типа удобно не попадают в одну из упомянутых категорий, имена должны быть выбраны, чтобы быть настолько значимыми насколько возможно в пределах ограничивания одной буквы. Упомянутые выше имена (E, K, T, V, X) не должен использоваться для параметров типа, которые не попадают в определяемые категории.

6.8.4 Имена методов

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

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

Имена методов не могут затенить или быть затенены другими именами (§6.5.7).

6.8.5 Имена полей

Имена полей, которые не являются final должен быть в смешанном случае с нижним регистром, сначала обозначают буквами и первые буквы последующих использованных для своей выгоды слов. Отметьте, что у хорошо разработанных классов есть очень немногие public или protected поля, за исключением полей, которые являются константами (final static поля) (§6.8.6).

У полей должны быть имена, которые являются существительными, именными группами, или сокращениями для существительных. Примерами этого соглашения являются поля buf, pos, и count из класса java.io.ByteArrayInputStream и поле bytesTransferred из класса java.io.InterruptedIOException.

Затемнение включения имен полей редко.

6.8.6 Постоянные Имена

Имена констант в интерфейсных типах должны быть, и final переменные типов классов могут традиционно быть, последовательность одного или более слов, акронимов, или сокращений, всего верхнего регистра, с компонентами, разделенными подчеркиванием"_"символы. Постоянные имена должны быть дескриптивными и весьма обязательно сокращенными. Традиционно они могут быть любой соответствующей частью речи. Примеры имен для констант включают MIN_VALUE, MAX_VALUE, MIN_RADIX, и MAX_RADIX из класса Character.

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

interface ProcessStates {
        int PS_RUNNING = 0;
        int PS_SUSPENDED = 1;
}
Затемнение включения постоянных имен редко:

6.8.7 Локальная переменная и Названия параметра

Локальная переменная и названия параметра должны быть короткими, все же значимыми. Они часто - короткие последовательности строчных букв, которые не являются словами. Например:

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

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


Содержание | Предыдущий | Следующий | Индекс Спецификация языка Java
Третий Выпуск

Авторское право © 1996-2005 Sun Microsystems, Inc. Все права защищены
Пожалуйста, отправьте любые комментарии или исправления через нашу форму обратной связи

free hit counter