Программирование на Java
Шрифт:
Допускается одновременно импортировать пакет и какой-нибудь тип из него:
import java.awt.*;
import java.awt.Point;
Может возникнуть вопрос, как же лучше поступать – импортировать типы по отдельности или весь пакет сразу? Есть ли какая-нибудь разница в этих подходах?
Разница заключается в алгоритме работы компилятора, который приводит каждое простое имя к полному. Он состоит из трех шагов:
* сначала просматриваются
* затем другие типы, объявленные в текущем пакете, в том числе в текущем модуле компиляции;
* наконец, просматриваются выражения, импортирующие пакеты.
Таким образом, если тип явно импортирован, то невозможно ни объявление нового типа с таким же именем, ни доступ по простому имени к одноименному типу в текущем пакете.
Например:
// пример вызовет ошибку компиляции
package my_geom;
import java.awt.Point;
class Point {
}
Этот модуль вызовет ошибку компиляции, так как имя Point в объявлении высшего типа будет рассматриваться как обращение к импортированному классу java.awt.Point, а его переопределять, конечно, нельзя.
Если в пакете объявлен тип:
package my_geom;
class Point {
}
то в другом модуле компиляции:
package my_geom;
import java.awt.Point;
class Line {
void main {
System.out.println(new Point);
}
}
складывается неопределенная ситуация – какой из классов, my_geom.Point или java.awt.Point, будет использоваться при создании объекта? Результатом будет:
java.awt.Point[x=0,y=0]
В соответствии с правилами, имя Point было трактовано на основе импорта типа. К классу текущего пакета все еще можно обращаться по полному имени: my_geom.Point. Если бы рассматривался безымянный пакет, то обратиться к такому "перекрытому" типу было бы уже невозможно, что является дополнительным аргументом к рекомендации располагать важные программы в именованных пакетах.
Теперь рассмотрим импорт пакета. Его еще называют "импорт по требованию", подразумевая, что никакой "загрузки" всех типов импортированного пакета сразу при указании импортирующего выражения не происходит, их полные имена подставляются по мере использования простых имен в коде. Можно импортировать пакет и задействовать только один тип (или даже ни одного) из него.
Изменим рассмотренный выше пример:
package my_geom;
import java.awt.*;
class Line {
void main {
System.out.println(new Point);
System.out.println(new Rectangle);
}
}
Теперь результатом будет:
my_geom.Point@92d342
java.awt.Rectangle[x=0,y=0,width=0,height=0]
Тип Point
Также корректен теперь пример:
package my_geom;
import java.awt.*;
class Point {
}
Таким образом, импорт пакета не препятствует объявлению новых типов или обращению к существующим типам текущего пакета по простым именам. Если все же нужно работать именно с внешними типами, то можно воспользоваться импортом типа, или обращаться к ним по полным именам. Кроме того, считается, что импорт конкретных типов помогает при прочтении кода сразу понять, какие внешние классы и интерфейсы используются в этом модуле компиляции. Однако полностью полагаться на такое соображение не стоит, так как возможны случаи, когда импортированные типы не используются и, напротив, в коде стоит обращение к другим типам по полному имени.
Объявление верхнего уровня
Далее модуль компиляции может содержать одно или несколько объявлений классов и интерфейсов. Подробно формат такого объявления рассматривается в следующих лекциях, однако приведем краткую информацию и здесь.
Объявление класса начинается с ключевого слова class, интерфейса – interface. Далее указывается имя типа, а затем в фигурных скобках описывается тело типа. Например:
package first;
class FirstClass {
}
interface MyInterface {
}
Область видимости типа - пакет, в котором он описан. Из других пакетов к типу можно обращаться либо по составному имени, либо с помощью импортирующих выражений.
Однако, кроме области видимости, в Java также есть средства разграничения доступа. По умолчанию тип объявляется доступным только для других типов своего пакета. Чтобы другие пакеты также могли использовать его, можно указать ключевое слово public:
package second;
public class OpenClass {
}
public interface PublicInterface {
}
Такие типы доступны для всех пакетов.
Объявления верхнего уровня описывают классы и интерфейсы, хранящиеся в пакетах. В версии Java 1.1 были введены внутренние (inner) типы, которые объявляются внутри других типов и являются их элементами наряду с полями и методами. Данная возможность является вспомогательной и довольно запутанной, поэтому в курсе подробно не рассматривается, хотя некоторые примеры и пояснения помогут в целом ее освоить.