GrabDuck

INTUIT.ru: Курс: Программирование на ..: Лекция №5: Имена. Пакеты

:

Введение

Имена (names) используются в программе для доступа к объявленным (declared) ранее "объектам", "элементам", "конструкциям" языка (все эти слова-синонимы были использованы здесь в их общем смысле, а не как термины ООП, например). Конкретнее, в Java имеются имена:

  • пакеты;
  • классы;
  • интерфейсы;
  • элементы (member) ссылочных типов:
    • поля;
    • методы;
    • внутренние классы и интерфейсы;
  • аргументы:
    • методов;
    • конструкторов;
    • обработчиков ошибок;
  • локальные переменные.

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

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

Имена

Простые и составные имена. Элементы

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

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

Далее классы и интерфейсы будут называться объединяющим термином тип (type).

Элементами пакета являются содержащиеся в нем классы и интерфейсы, а также вложенные пакеты. Чтобы получить составное имя пакета, необходимо к полному имени пакета, в котором он располагается, добавить точку, а затем его собственное простое имя. Например, составное имя основного пакета языка Java – java.lang (то есть простое имя этого пакета lang, и он находится в объемлющем пакете java ). Внутри него есть вложенный пакет, предназначенный для типов технологии reflection, которая упоминалась в предыдущих главах. Простое название пакета reflect, а значит, составное – java.lang.reflect.

Простое имя классов и интерфейсов дается при объявлении, например, Object, String, Point. Чтобы получить составное имя таких типов, надо к составному имени пакета, в котором находится тип, через точку добавить простое имя типа. Например, java.lang.Object, java.lang.reflect.Method или com.myfirm.MainClass. Смысл последнего выражения таков: сначала идет обращение к пакету com, затем к его элементу – вложенному пакету myfirm , а затем к элементу пакета myfirm – классу MainClass. Здесь com.myfirmсоставное имя пакета, где лежит класс MainClass, а MainClassпростое имя. Составляем их и разделяем точкой – получается полное имя класса com.myfirm.MainClass.

Для ссылочных типов элементами являются поля и методы, а также внутренние типы (классы и интерфейсы). Элементы могут быть как непосредственно объявлены в классе, так и получены по наследству от родительских классов и интерфейсов, если таковые имеются. Простое имя элементов также дается при инициализации. Например, toString(), PI, InnerClass. Составное имя получается путем объединения простого или составного имени типа, или переменной объектного типа с именем элемента. Например, ref.toString(), java.lang.Math.PI, OuterClass.InnerClass. Другие обращения к элементам ссылочных типов уже неоднократно применялись в предыдущих главах.

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

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

Во-первых, в выражении объявления (declaration) идентификатор еще не является именем. Другими словами, он становится именем после первого появления в коде в месте объявления.

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

country.getCity().getStreet();

В данном примере getStreet является не именем, а идентификатором, так как соответствующий метод вызывается у объекта, полученного в результате вызова метода getCity(). Причем country.getCity как раз является составным именем метода.

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

num:
   for (int num = 2; num <= 100; num++) {
      int n = (int)Math.sqrt(num)+1;
      while (--n != 1) {
         if (num%n==0) {
            continue num;
         }
      }
      System.out.print(num+" ");
   }

Результатом будут простые числа меньше 100:

2 3 5 7 11 13 17 19 23 29 31 37 41 43 47 53 59 61 67 71 73 79 83 89 97

Мы видим, что здесь применяются одноименные переменная и метка num, причем последняя используется для выхода из внутреннего цикла while на внешний for.

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

Область видимости (введение)

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

Например:

class Point {
   int x,y;

   int getX() {
      return x; // простое имя
   }
}
class Test {
   void main() {
      Point p = new Point();
      p.x=3; // составное имя
   }
}

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

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