Пакеты и интерфейсы. Формат модуля трансляции Java
Программист пишет исходные тексты Java-программ (application и applet) в исходных файлах, которые мы назвали модулями трансляции. При этом в одном таком модуле может быть определено множество разных классов. После трансляции, для каждого из них будет создан свой байт-код, который будет помещен в отдельный файл. Если мы пишем applet, то при его тестировании скорее всего на этапе выполнения появится ошибка о том, что некоторый класс исполняющей системой не обнаружен. Данная проблема решается либо путем размещения всех классов в стандартном месте, либо объединением их в пакеты. Пакеты - это своеобразные библиотеки Java-кода. При этом программы из разных пакетов могут называться одинаково. Пакеты иерархически подчинены и явным образом включаются в текст программы на Java.
Общая форма исходного файла Java выглядит следующим образом:
packagepack0[.pack1[.pack2]] importpack0[.pack1[.pack2]] ... importpack0[.pack1[.pack2]] publicclassclass_nameextandsclass_name { // classbody } privateclassclass_name { // classbody } ... privateclassclass_name { // classbody }
Как видно из этого примера файл может начинаться оператором packаge, который определяет принадлежность класса некоторому пакету. За оператором package следуют операторы import, которые в явном виде указывают на импортируемые описания классов из других пакетов. Затем может быть определен только один публичный класс, за которым можно определить любое количество приватных классов. Вообще говоря, Java позволяет защищать данные классов от доступа. Для этой цели используется три модификатора private, public и protected.
Public определяет, что объекты данного класса пакета доступны для всех прочих классов. Это самый высокий уровень доступности. Если указан модификатор private, то доступ к переменным и методам класса разрешен только из объектов данного класса. Если используется модификатор protected, то здесь наблюдается совместимость сверху вниз, т.е. к переменным и методам можно обращаться как из объектов, являющихся реализациями подклассов, так и из объектов классов и их подклассов, принадлежащих тому же пакету. Строгое подчинение определяется в том случае, когда protected и private используются совместно. Существует и доступность по умолчанию, в которой подклассам данного класса из других пакетов в доступе к элементам класса отказано.
Вообще говоря, все эти ограничения следует использовать не столько для ограничения доступности, сколько для определения области видимости и действенности переменных. В частности, Вирт критикует само понятие безопасности, связанное с модификаторами защищенности, поскольку с его точки зрения, это только сбивает с толку. Ограничения используются в том смысле, что они повышают устойчивость программы от ошибок, связанных с областями действия переменных и методов, а не со взломами операционных систем или чем-либо подобным. Однако, более подробно на разграничениях доступа останавливаться не будем и перейдем к другому важному элементу Java - интерфейсам.
Интерфейс - это спецификация обмена данными между классами. Фактически они представляют из себя просто список объявлений методов. С интерфейсом разработчики апплетов встречаются сразу же как только захотят написать многопоточный applet. А это необходимо, например, для создания бегущей строки.
Оператор interface имеет вид:
interfaceinterface_name { typemethod_name (parms_list); typefinal_variable = value; }
При вызове метода, определенного в интерфейсе, класс должен быть объявлен с оператором implements. Например, бегущая строка "Hello, Java" реализована с применением данного оператора.
importjava.applet.*; importjava.awt.*; publicclasshelloextendsAppletimplementsRunnable { intx = 0; inty = 0; intstart_x = 0; intstart_y = 0; Threadnew_thread = null; Stringmessage = "Hellobody!!!"; publicvoidinit () { y = size ().height; x = size ().width; start_x = x; start_y = y; } publicvoidstart () { new_thread = newThread (this); new_thread.start (); } publicvoidrun () { while (true) { repaint (); x -= 10; if (x<0) { x=start_x; } try { Thread.sleep (100); } catch (InterruptedExceptione) { } } } publicvoidpaint (Graphicsg) { Fontnew_font = newFont ("TimesRoman",1,48); g.setFont (new_font); g.drawString ("Hello, Java.",x,y/2); } }
В приведенном примере программа, в данном случае applet, расширяет класс Applet и применяет интерфейс Runnable для того, чтобы реализовать метод run.
При трансляции программ и сборки их в пакеты следует помнить, здесь разработчик встречается с особенностями реализации средств разработки Java для различных платформ. Названия иерархий в пакетах Java должны совпадать с директориями и поддиректориями, в которых эти пакеты размещаются, при этом корень определяется переменной окружения CLASSPATH. Часто наиболее распространенным значением этой переменной является:
CLASSPATH=".;C:\your_path;C:\java\classes;\C:\java\classes\classes.zip"
Заархивированный файл в пути не должен смущать, т.к. JavaDevelopmentKit умеет работать с такими файлами.