Основы языка Java: классы, методы и интерфейсы

П

Ора начать разбираться в некоторых деталях синтаксиса языка Java. Этот про­цесс начнется здесь и растянется на три ближайших главы. Вообще говоря, Java — восхитительно ясный и логичный язык. Если вы имеете за плечами некото­рый опыт программирования, то вам будет легко понять большую часть синтаксиса этого языка. Однако в Java есть и несколько тонкостей, на которых легко споткнуть­ся, если не знать об их существовании.

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

Наша цель на протяжении трех ближайших глав — разобраться с этими базовы­ми синтаксическими элементами, дабы глубже понять и язык, и сам JBuilder. В этих главах я постараюсь "сгладить" большинство зигзагов, которые могут встретиться на вашем пути, и таким образом расчистить дальнейший путь.

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

По прочтении этой главы вы сможете делать следующее:

■ Создавать простой Java-класс с областью видимости по умолчанию либо от­крытый класс.

■ Добавлять в класс новый метод.

■ Создавать экземпляр класса.

■ Вызывать добавленный в класс метод из стандартного приложения JBuilder.

Базовая аналогия для следующих трех глав

Аналогии не должны быть обязательно логичными. Наоборот, это ментальный прием, помогающий понять новые концепции за счет проведения параллелей меж­ду элементами знакомой идеи и элементами идеи незнакомой. В данном случае я хочу провести некоторые аналогии между написанием программы и написанием книги.

Базовые элементы печатного издания, от меньших к большим выглядят так: сло­ва, предложения, абзацы, разделы, главы и книги. Аналогично, программный код состоит из идентификаторов, операторов, методов, классов, пакетов и JAR-файлов. Моя довольно грубая, и даже, пожалуй, произвольная, аналогия проводит следую­щие параллели:

Печатный текст Программный код

Предложения Операторы

Абзацы Методы

Разделы Классы

Главы Пакеты

Книги JAR-файлы

Подобного рода аналогии могут сбить с толку. Не понимайте их слишком бук­вально, особенно если они относительно свежи в программировании.

Например, я не утверждаю, что оператор программного кода и предложение в книге — это одно и то же Я лишь предполагаю, что они в чем-то подобны.

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

примечаниеIaiHaiiii-*ним «а Обычно мы можем полностью держать в уме одновременно все дета­ли простого оператора программы. Аналогично, обычно мы можем полностью держать в уме одновременно все детали простого предложения. Очень способные индивидуумы могут полностью держать в уме одновременно все детали даже относительно сложных абзацев, точно так же как очень способные программисты могут обдумывать или пред­ставлять во всех деталях какой-нибудь сложный метод. Но что касается более масштаб­ных порций, наподобие целого класса или раздела, то большинство людей может охва­Тить лишь общую идею.

Любопытно, что можно буквально видеть пределы среднего человеческого ума, читая в газете или журнале цитаты выступлений, которые не были подготовлены за­ранее. Например, некоторые бывшие президенты США говорили фрагментами предложений. В импровизированной речи они обычно не могли составить полное предложение, не запутавшись в нем. Но другие американские президенты могли без подготовки говорить не только завершенными предложениями, но и целыми абза­цами. Такая способность встречается нечасто. Так же нечасто встречаются програм­мисты, которые могут четко и конкретно думать в терминах целых классов. Как пра­вило, большинство программистов с трудом осмысливают сразу весь метод, состоя­щий уже из 10—15 строк. Одна из важнейших причин разбиения программ на разделы как раз и состоит в том, чтобы помочь преодолеть эту проблему. Большин­ство из нас не может держать в голове одновременно большое количество сложных идей. Поэтому мы пытаемся справиться с проблемой, деля код на относительно не­большие синтаксические элементы.

Классы являются неотъемлемой частью хорошего программирования, так же как разделы глав помогают написанию хорошего текста. Некоторые пишут программы, которые являются, по сути, ни чем иным, как одним длинным абзацем, или, в луч­шем случае, последовательностью абзацев без подзаголовков, которые могли бы по­мочь читателю уяснить структуру текста. Эти программисты совершают ошибку, не используя классы для разбиения кода на понятные разделы приемлемых размеров. Такой код будет работать, так же как и вы поняли бы мой текст, если бы я написал его одним длинным абзацем или не использовал подзаголовки для выделения раз­личных разделов текста. И все-таки "бесклассовый" код обычно плохо структуриро­ван и затруднен для понимания.

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

У объектно-ориентированного программирования имеется множество досто­инств. Но главное его достоинство состоит в том, что оно позволяет разбить про­граммный код на порции, с которыми можно справиться. Мы, программисты, бо­ремся с теми же проблемами, что и политики, которые не могут говорить закончен­ными предложениями, хотя, надеюсь, программисты справляются лучше. Программирование — сложное занятие, а возможности нашего разума, к сожале­нию, ограничены. Разбивая код на отдельные синтаксические элементы, мы облег­чаем себе задачу преодоления этой сложности.

Историю программирования можно рассматривать как всего лишь борьбу за раз­работку корректного синтаксиса для разбиения программ на поддающиеся управле­нию части. Структурное программирование дало нам функции, процедуры и моду­ли. Объектно-ориентированное программирование принесло классы. Далее в этой книге мы рассмотрим даже еще более сложный инструмент, называемый компонен­том, или JavaBean.

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

Классы в Java

Чтобы текст получился ясным и понятным, я не буду проводить здесь исчерпы­вающее исследование классов, а только основные факты, которые необходимо знать. Авторы других книг стараются охватить всю тему классов в одной или в не­скольких последовательных главах. Я считаю, что проблема такого подхода кроется в том, что в нем смешаны вопросы начального уровня программирования и сложные вопросы. Это может быть полезным для опытных программистов, которым нужно лишь быстрое введение в новый язык, но не годится для новичка, который пытается разобраться в основных понятиях, нужных для того, чтобы приступить к написанию программного кода. Поэтому в данной главе я буду избирательно излагать только основные факты о классах.

В Java почти все представляет собой классы. Исключениями являются несколько операторов, несколько основных типов, таких как целые числа, логические значе­ния, символы и числа с плавающей запятой, и несколько отдельных элементов на­подобие пакетов и операторов импорта. Но вообще классы играют в программиро­вании на Java очень большую роль. Существенная зависимость Java от классов — очень хорошее свойство этого языка. Это один из самых больших источников его силы.

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

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

Базовый синтаксис класса

Сейчас уже пора углубиться в некоторые детали. Вот базовый синтаксис объявле­ния класса:

Class MyClass

{

}

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

Некоторые предпочитают ставить первую фигурную скобку в конце первой стро­ки объявления класса:

Class MyClass {

}

Другие предпочитают стиль, показанный в первом примере. Синтаксически оба примера верны. Я пользуюсь первым способом, поскольку считаю, что его проще читать. Если вы считаете, что легче читать вторую запись, пользуйтесь ей. Хорошие редакторы, например, Visual SlickEdit, содержат Форматировщики исходного кода (Source Beautifiers), которые могут переделать ваш код из одного стиля в другой в ре­зультате щелчка на одной кнопке. В Internet можно найти много бесплатных инст­рументов, которые выполнят эту работу за вас.

Область видимости класса: по умолчанию или открытый класс

Область видимости (Scope) части кода определяет, где известна эта часть. Класс с очень широкой областью видимости может быть виден во всей программе. Класс с более ограниченной областью видимости может быть виден только из конкретного пакета. Когда я говорю, что класс может быть "виден", я имею в виду то, что он мо­жет быть вызван. Если вы не можете "видеть" класс в силу его узкой области видимо­сти, то не сможете пользоваться этим классом. Вы не сможете создавать экземпляры этого класса и вызывать его методы.

Класс, который я назвал MyClass, Имеет область видимости по умолчанию; дру­гим словами, он не объявлен как закрытый или открытый. По умолчанию классы могут быть видны только в пределах текущего пакета.

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

Вот еще одно объявление класса:

Public Class MyClass

{

}

Перед этим классом находится ключевое слово public. Классы, объявленные та­ким образом, могут быть видимы и из файлов текущего пакета, и из других пакетов. Конечно, я еше не определил, что такое пакет, но вспомните, что это приблизи­тельно то же самое, что и каталог. Если вы находитесь в каталоге А, вы можете ви­деть открытые классы, объявленные не только в текущем каталоге, но и в каталогах В, C, D и т. д. Вы также можете видеть все методы этих классов, объявленные как от­крытые.

Открытые классы должны находиться в своих собственных Java-файлах, и эти файлы должны иметь то же имя, что и класс. Например, только что объявленный класс MyClass Должен находиться в файле исходного кода с именем MyCiass. Java

Нельзя, чтобы в одном исходном файле находились два открытых класса. Но во­обще в одном и том же исходном файле могут находиться более одного класса. Если в одном файле имеется один открытый класс и один класс с областью видимости по умолчанию, и вы скомпилируете этот исходный файл, то в результате получатся два откомпилированных файла с расширением .Class. Для каждого объявленного клас­са имеется свой файл с расширением .Class, Хотя они и объявлены в одном исход­ном Java-файле.

Вложенные классы: в этой главе не рассматриваются

В Java классы можно помещать внутри других классов:

Class Foo

{

Int ɪ;

Static class Nested {

Int J;

}

}

Существует несколько вариантов синтаксиса этого типа, и у каждого из них есть свой оттенок значения. Но в этой книге я буду редко применять такую запись. В ча­стности, я буду использовать ее, когда буду рассказывать о псевдоперечислимых ти­пах, определяемых в виде класса.

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

Создание и уничтожение классов

В Java, как и в Delphi, но не как в C++, требуется, чтобы вы создавали экземпля­ры большинства классов до того, как их использовать. Вот синтаксис создания эк­земпляра класса:

MyClass MyClass = New MyClass();

За одним серьезным исключением, вы ничего не сможете сделать с классом, не создав его предварительно с помощью оператора New. На самом деле в этом случае в куче создается объект; т. е. вы распределяете память для этого объекта. Но, так же как и в Delphi, но не как в C++, при обращении к этому объекту указатель на него не нужен. Вместо него используется точечная запись:

KtyClass. DoSome Thing ;

В отличие от Delphi, программистам на Java обычно не требуется освобождать созданные экземпляры класса: за них это делает система. На самом деле Java авто матически освобождает почти всю выделяемую память. Эта замечательная система называется сборкой мусора (garbage collection).

Иногда при запуске Java-программы она "на секунду теряет сознание", те. ее вы­полнение чуть-чуть приостанавливается. Для стандартной Windows-программы, на­писанной на C или Pascal, это обычно значит, что Windows работает со swap-файлом (файлом подкачки). Для Java-программы это зачастую означает, что работает сбор­щик мусора. Конечно, при работе Java-программ под Windows это может значить, что работает Или swap-файл, Или сборщик мусора. Выбирайте сами!

Объявление методов класса

В языке Java не бывает самостоятельных функций, процедур или подпрограмм. Все они должны быть частью какого-то класса. Эти элементы, принадлежащие клас­су, называются Методами (Methods). На практике это выглядит так:

Class MyClass

{

String getstring()

{

Return "Это строка";

}

}

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

Вышеприведенное объявление класса MyCiass Содержит один метод с именем Getstring. Вызов этого метода возвращает строку, содержащую слова "Это стро­ка". Другими словами, метод Getstring Это такое маленькое устройство, пред­назначенное для возврата этих двух слов. Точнее, он возвращает слова "Это стро­ка". Синтаксический элемент Return Указывает компилятору, что за ним следует значение, которое функция "возвращает” пользователю.

Работа со строками

В предыдущем абзаце прозвучало слово "строка". Что это такое? Вообще говоря, Строка (String) является частью текста, встроенной в программу. Если вам необходи­мо что-то сообщить пользователю "человеческим языком", то вы создадите строку.

Конечно, создаваемая вами строка может содержать не только слова, но и числа, бессмысленные последовательности букв или другое содержимое, что делает поня­тие строки несколько расплывчатым. Чтобы лучше понять, что такое строка, может быть, лучше говорить в терминах синтаксиса языка Java.

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

String getstring()

{

Return "Я помню чудное мгновенье: \п" +

"Передо мной явилась ты. " ;

}

Обратите внимание, что здесь в конце первой строки добавлен символ "\п", Из­вестный как возврат каретки или перевод строки. Это сделано для того, чтобы вто­рая строка не выводилась на той же строке выводимого текста, что и первая. (В рус­ском языке словом "строка" переводится и слово "string" (текстовая часть програм­мы), и слово "line" (строка печатного текста), что может вызвать некоторую путаницу — Прим, перев.) По аналогичной причине иногда в конец строки необхо­димо добавлять пробел, чтобы следующая строка не выводилась впритык к первой:

String getstring()

{

Return "Это строка. " +

"Пожалуй, да. ";

}

Без пробела результирующая строка выглядела бы так: "Это строка. пожалуй, да." Но если вставить пробел, строка будет выведена так, как надо: "Это строка. Пожалуй, да."

Объявление типа метода

Мы знаем, что метод getstring возвращает строку (string), потому что он так объявлен:

String getstring()

Если бы мы написали метод, возвращающий целое число, то объявление выгля­дело бы так:

Int getstring()

В этом примере слово string заменено словом int. Это значит, что функция возвращает не строку, а целое число.

Слово string написано с большой буквы, поскольку это класс, а слово int — с маленькой буквы, поскольку это простой тип. О простых типах и классе string еще пойдет разговор в следующей главе.

Слово Myciass Также написано с большой буквы, потому что в языке Java суще­ствует соглашение, в соответствии с которым имена всех классов начинаются с заг­лавных букв. Если вы создаете имя класса из нескольких слов, то в соответствии с тем же соглашением каждое слово начинается с заглавной буквы: MyCiass. Это час­то называется camel caps (к сожалению, эквивалентного выражения в русском языке нет — Прим, перев.)

Слово getstring начинается с маленькой буквы, потому что, по соглашению, в Java все имена методов начинаются с маленькой буквы. Если имя, выбранное вами для метода или переменной, состоит более чем из одного слова, то второе и все пос­ледующие слова должны начинаться с больших букв: myMethod, myVariable, my Fan Су Variable. Если вы еще не знаете, что такое переменная — не беспокойтесь, об этом будет рассказано в следующей главе.

О методе getstring необходимо сказать еще кое-что. Рассмотрим следующее определение класса:

Public class MyClass

{

Public String getstring ()

{

Return "Это строка";

}

}

Как видите, этот класс объявлен открытым (public). Это значит, что он может быть виден и в текущем, и в других каталогах. Другими словами, он может быть ви­ден и в текущем, и в других пакетах. Метод getstring также объявлен открытым. Если метод не объявить открытым, то его будет невозможно вызвать из класса, нахо­дящегося в другом каталоге. Я могу создать экземпляр класса, поскольку этот класс объявлен открытым. Но если бы метод getstring был объявлен с областью видимо­сти по умолчанию, то я не смог бы вызвать его из класса, расположенного в другом каталоге. Другими словами, если MyClass имеет область видимости по умолчанию, и getstring имеет область видимости по умолчанию, то я могу создать экземпляр класса MyClass, НО Не могу вызвать метод getstring. Объявляя getstring откры­тым, я обеспечиваю возможность вызвать этот метод из класса, находящегося в дру­гом каталоге — т. е. из класса в другом пакете.

Использование классов в приложениях

Пусть у нас имеется класс, содержащий метод, который выполняет что-нибудь полезное, например, возвращает какую-то строку. Что можно сделать с этим клас­сом?

В листинге 8.1 приведен фрейм (называемый также формой или окном) из эле­ментарного приложения JBuilder, который использует созданный нами класс. По­смотрите на этот листинг, а затем я объясню, как его создать.

Листинг 8.1. Исходный файл Frameljava из программы MethodTest

Package methodtest;

Import j ava. awt.*;

Inport j ava. awt. event.*;

Import j avax. swing.*;

Public class Framel extends JFrame

{

JPanel ContentPane;

JButton jButtonl = new JButton();

MyClass myClass = new MyClass () ;

JTextArea jTextAreal = new JTextArea();

∕ I Создание Фрейма

Public Framel()

{

EnableEvents(AWTEvent. WINDOW_EVENT_MASK); Try {

Jblnit() ;

1

Catch(Exception e)

{

E. printStackTrace();

)

1

∕∕ Инициализация Компонентов Private void JbInit () throws Exception {

JButtonl. setText("jButtonl");

JButtonl. setBounds (new Rectangle (113, 124, 155, 29)) ;

JButtonl. addActiOnListener(new Framel_jButtonl_actionAdapter(this));

ContentPane= (JPanel) this. getContentPane();

ContentPane. SetLayout(null); this. setSize (new Dimension (400, 300)) ; this. setTitle("Frame Title"); jTextAreal. setText (,, jTextAreal") ;

JTextAreal. setBounds (new Rectangle (70, 27, 248, 88)) ;

ContentPane. add(jButtonl, null); contentPane. add(jTextAreal, null);

)

∕∕ Переопределено для выхода при закрытии окна protected void processWindowEvent (WindowEvent е)

{

Super. ProcessWindowEvent(e) ;

If (e. getID() == WindowEvent-WlNDOWJZLOSING)

{

System. exit(О);

}

)

Void jButtonl_actionPerformed(ActionEvent e)

{

JTextAreal. setText(myClass. getString());

)

)

Class MyClass

{

Public String getString ()

{

Return "Я помню чудное мгновенье: ∖n" +

"Передо мной явилась ты" ;

}

}

// Вспомните, что в моей среде JBuilder я воспользовался пунктом меню ∕∕ Project I Default Options на странице настройки стиля кода и выбрал // для обработки событий Standard adapters

Class Framel_jButtonl_actionAdapter implements j ava. awt. event. ActionListener

{

Framel adaptee;

Framel_jButtonl_actionAdapter(Framel adaptee)

{

This, adaptee = adaptee;

)

Public void actionPerformed (ActionEvent e)

{

Adaptee. jButtonl_actionPerformed(e);

)

)

Если вы не помните, как создать заготовку этого проекта, обратитесь к главе 3, а после создания проекта вернитесь к этому месту.

Перейдите в конец файла Framel. java и вставьте объявление класса MyClass:

Class MyClass {

String getString ()

{

Return "Я помню чудное мгновенье: \п" +

"Передо мной явилась ты";

}

}

В проект нужно также добавить код объявления экземпляра вашего класса и его инициализации. Перейдите в начало описания Framel И добавьте объявление свое­го класса:

Public class Framel extends JFrame

{

JPanel ContentPane;

MyClass myClass = new MyClass () ;

∕∕ здесь опущено много-много кода

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

Показанный мной код сначала объявляет экземпляр объекта:

MyClass MyClass

Затем этот экземпляр создается: MyClass = New MyClass();

Все это можно объединить в один оператор:

MyClass MyClass = New MyClass();

Применение Оператора New Распределяет память под экземпляр класса. Поэтому процесс состоит из двух шагов: сначала экземпляр класса объявляется, а затем со­здается.

Скомпилируйте ваш проект, дабы удостовериться, что вы верно ввели объявле­ние класса. Для этого откройте меню Project и выберите либо пункт Make project methodtest, либо Make frame1.java. В первом случае будет собрано все приложение, а во втором — только Framel. Java. Для наших целей годится любой способ.

Если компиляция прошла без ошибок, щелкните на странице Design внизу ре­дактора. Вы перейдете в режим конструирования. Осторожно: не попадите на стра­ницу AWT. Мы создаем приложение, а не аплет. В результате нам не нужно будет беспокоиться о совместимости со старыми версиями JDK. Вместо этого вы сможете выбирать элементы управления со страницы Swing палитры компонентов. (Конеч­но, элементы Swing можно использовать и в аплете. Единственная проблема состо­ит в том, что некоторые современные HTML-браузеры могут не распознать этот ап­лет.)

В нашем конкретном случае потребуется выбрать элементы JButton и JTextArea. Разместите их как показано на рис. 8.1.

Чтобы ваши элементы выглядели так же, как на рисунке, сначала проверьте, включена ли опция BorderLayout. Для этого щелкните в панели структуры на строке ContentPane, и затем с помощью инспектора установите компоновку в BorderLayout. (Панель структуры — это второе (нижнее) из двух окон слева на экране. На рис. 8.1 видно, что элемент ContentPane выделен в иерархическом списке элементов, отобра­жаемых в панели структуры.)

Щелкните на элементе jButton1, и с помощью инспектора JBuilder установите его привязку либо в North (вверху), либо в South (внизу), в зависимости от собственных предпочтений. Установите привязку текстовой области в Center (в центре).

рис. 8.1. так
выглядит главный фрейм приложения во время
конструирования

Компоновки более подробно будут описаны в нескольких главах части III, "Ос­новы JBuilder". В этих главах будет показано, как в окончательном коде избежать ис­пользования ограниченной пустой компоновки.

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

Void jButtonl_actionPerformed(ActionEvent Е)

{

}

Добавьте в него одну строку:

Void jButtonl_actionPerformed(ActionEvent Е)

{

JTextAreal. setText(myClass. getString ());

J

Hy вот, ваша программа готова. Теперь вы можете откомпилировать и запустить ее с помощью зеленой кнопки "Выполнить". После запуска щелкните на созданной вами кнопке, и вы увидите текст из класса, находящегося в компоненте JTextArea.

Конструкторы

Если вы еще способны благополучно усвоить последний глоток синтаксического жаргона в этой главе, то я хотел бы добавить краткое объяснение конструкторов. Конструкторы (Constructors) — Это методы, добавляемые в класс, которые автомати­чески выполняются при создании класса.

Рассмотрим следующее объявление:

Package Sammy; Public Class MyClass

{

String myString; public MyClass()

{

MyString = "Я помню нудное мгновенье :\п" +

" Передо мной явилась ты.\п" +

"Как мимолетное виденье,\п" +

"Как гении чистой красоты. \п” +

"В томленьях грусти безнадежной,\п" +

"В тревогах шумной суеты\п" ;

"Звучал мне долго голос нежный\п" +

"И снились милые черты.\п";

}

Public String getString()

{

Return myString;

}

}

Этот класс содержит конструктор MyClass. Конструктор класса всегда должен иметь то же имя, что и сам класс.

Конструктор вызывается автоматически при создании экземпляра класса. По­этому он является наиболее подходящим местом для выполнения инициализации объектов.

В данном случае обратите внимание, что я объявил переменную myString и ини­циализирую ее в конструкторе. Тогда в методе getstring мне остается только вер­нуть эту инициализированную строку.

В языке Java любая неинициализированная в конструкторе переменная имеет нулевое значение. Таким образом, если вы объявите поле вашего класса как int и не присвоите ей явно значения, оно при создании класса автоматически примет нуле­вое значение. Строкам присваивается не пустая строка, а пустое значение. Про классы, не инициализированные явно, говорят, что они имеют пустое значение — это просто другой способ сказать, что они не инициализированы.

Поскольку Java автоматически инициализирует все переменные класса нулевым значением, пустым значением или каким-то аналогичным значением по умолча­нию, то в конструкторе можно не инициализировать переменные, если их нужно просто "обнулить". Специально инициализируйте переменные только в том случае, когда им необходимо присвоить какое-то явное значение, отличное от нуля, пусто­го значения и т. д. В нашем случае это действительно необходимо, поэтому я и со­здал конструктор.

Открытые классы, ваш первый пакет

Обратите также внимание, что класс MyClass объявлен открытым. Более того, я объявил открытыми и конструктор, и метод getstring. В результате вы можете по­местить этот файл в отдельный каталог и вызывать его из любого текущего каталога.

Как было сказано в предыдущем разделе, я назвал пакет, содержащий этот файл, Sammy. В именах пакетов почти всегда используются маленькие буквы. Это значит, что файл с именем MyClass. java должен находиться в каталоге с именем Sammy. На­
пример, вы можете наряду с каталогом, содержащим файл Framel. java, создать другой каталог и назвать его Sammy. Затем вы можете скопировать этот файл во вновь созданный каталог. Теперь добавьте в свой текущий проект новый файл. Для этого в IDE щелкните на кнопке Add to the project. На этой кнопке изображена маленькая папка с зеленым крестиком сверху (¾j). Или, если вам так больше нравится, выбе­рите пункт меню Project ∣ Add to Project.

Теперь нужно внести некоторые изменения в исходный файл Framel. Java. В Са­мом начале этого файла добавьте оператор импорта пакета Sammy:

Package untitled7; import java. awt.*; import java. awt. event.*; import javax. swing.*; import untitled7.sammy.*;

Теперь удалите изначальное объявление класса MyClass, которое вы вводили ра­нее в конце файла Framel. java:

Class MyClass

{

Public String getString()

{

Return "Я помню чудное мгновенье:∖n" +

"Передо мной явилась ты";

I

}

Это объявление больше не нужно, поскольку класс теперь объявлен в файле MyClass. java, находящемся В каталоге Sammy.

Теперь можно сохранить все изменения и запустить программу. Возможно, что с новым методом getstring, возвращающим более длинную строку, вам придется в режиме конструирования увеличить размер JTeχtArea, Чтобы во время выполнения программа выглядела корректно.

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

Наследование

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

Рассмотрим следующие объявления:

Class Foo

{

Void f oobar ()

system, err .print in ("увидеть в крохотной песчинке мир") ;

{

}

}

Class Goober extends Foo

{

Void foobar()

{

System. err. printin("И райский сад в цветке невзрачном") ;

}

}

Говорят, что класс Goober Расширяет {Extends) класс Foo. Это следует из того, что в его объявлении присутствует слово Extends:

Class Goober extends Foo

В данном примере класс Foo Является базовым (или родительским — parent), а класс Goober Производным (или дочерним — child). Поэтому еще говорят, что класс Goober Наследует {Inherit) возможности класса Foo.

В этом конкретном примере интересно то, что и в классе Goober, И в классе Foo Присутствует метод Foobar. В нескольких следующих абзацах будет рассказано, как Java управляется с такими ситуациями, т. е. вы узнаете, который из этих двух мето­дов будет вызван при различных внешних обстоятельствах.

примечаниеВ данном примере, если вы создадите экземпляр класса Foo, то вызов метода foobar выведет сообщение "Увидеть в крохотной песчинке мир". Но если вы со­здадите экземпляр класса Goober, То вызов метода Foobar Выведет слова "и Райс­кий сад в цветке невзрачном". Говорят, что второе вхождение метода Foobar Пе­рекрывает (override) первое вхождение. Экземпляр метода Foobar Из класса Goober Вызывается вместо экземпляра метода Foobar Из класса Foo.

Вышеприведенный пример иллюстрирует тот факт, что в Java все мето­ды по умолчанию объявлены как виртуальные (virtual). Метод называется виртуальным, если он может либо быть перекрытым другим методом с тем же именем, либо перекрыть другой метод с таким же именем. В языке Java, а вообще-то и во всех объектно-ориен­тированных языках, методы производного объекта перекрывают методы базового объекта, если их имена совпадают. Поскольку класс Goober является производным по отношению к классу Foo, то метод Goober. foobar() перекрывает метод Foo.Foobar().

Рассмотрим теперь несколько измененный класс Goober:

Class Goober extends Foo {

Void foobar ()

{

Super. foobar ();

System. err. println("И райский сад в цветке невзрачном") ;

)

}

Создайте экземпляр класса Goober и вызовите его метод foobar (). Теперь про­грамма выведет результаты вызовов обоих вхождений метода foobar ():

Увидеть в крохотной песчинке мир И райский сад в цветке невзрачном

Вызов Super.Foobar() из метода Goober. foobar() вызывает метод foobar(), который находится в классе Foo. Здесь слово "super" означает запрос на вызов фун­кции базового класса

Рассмотрим следующее объявление:

Class Foo

{

Final void foobar()

{

System, err. prin tin ("Увидеть в крохотной песчинке мир") ;

}

1

Class Goober extends Foo

{

Void f oobar ()

{

System. err. println("И райский сад в цветке невзрачном") ;

}

}

Говорят, что второй класс является производным от первого, или второй класс расширяет первый. Класс Goober является потомком класса Foo, и в обоих классах присутствует метод foobar. В приведенном примере содержится ошибка. В классе Foo Метод Foobar Объявлен окончательным (final). Это значит, что класс Goober Не может перекрывать его Метод объявляется окончательным, если необходимо подчеркнуть мысль, что он не может быть перекрыт в производных классах.

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

Вот еще один пример, который нет необходимости понимать:

Class Foo

{

Void foobar ()

1

System. err. println("Увидеть в крохотной песчинке мир") ;

)

)

Final class Goober extends Foo

{

Void foobar ()

{

System. err. println("И райский сад в цветке невзрачном") ;

)

}

Класс Goober Является производным от класса Foo. Вы не можете создать класс, производный от класса Goober, поскольку он объявлен окончательным. Если вы не хотите, чтобы у класса были потомки, вы можете эффективно "стерилизовать" его, вставив в его заголовок ключевое слово final.

Интерфейсы

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

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

Вот пример простого интерфейса и класса, реализующего этот интерфейс:

Interface Foo

{

Void foobar() ;

Class Goober implements Foo

Public void foobar()

{

System, err .print In ("Увидеть в крохотной песчинке мир") ;

)

}

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

1. Foo объявлен с ключевым словом interface, а не class.

2. Интерфейс Foo не содержит реализации метода foobar(). Это определяющее свойство интерфейса, Его методы не реализованы. Обратите внимание, что метод Goober. foσbar() объявлен открытым (public). Все методы интерфей­сов по умолчанию объявляются открытыми. Смысл заключается в том, что интерфейс Foo объявляет общедоступный стандарт, который должен быть ре­ализован в классе Goober. Чуть ниже я расскажу об этом подробнее.

3. В классе Goober используется ключевое слово implements, а не extends. Если класс реализует интерфейс, то он определяет методы, объявленные в этом интерфейсе. В частности, метод Goober. foobar() является реализаци­ей метода foobar(), объявленного в интерфейсе Foo.

Синтаксис интерфейса достаточно прост для понимания. Если кто-то что-то и не понимает в интерфейсах, то обычно не потому, что он действительно не понима­ет, как объявить или реализовать интерфейс. C этим-то все просто. Единственное непонятное здесь место — почему интерфейсы создаются До реализации.

Одно из основных применений интерфейсов состоит в определении стандарта. Если какой-либо класс реализует "интерфейс", то, по крайней мере, вы кое-что зна­ете о том, кок он будет себя вести: он будет вести себя в соответствии с методами, объявленными в реализуемом им "интерфейсе".

Здесь может помочь следующая аналогия. Почти у всех автомобилей есть руль, акселератор и тормоз. Поэтому можно сказать, что автомобили реализуют "интер­фейс" руль-газ-тормоз. Все мы умеем управлять автомобилем, потому что все авто­мобили ведут себя так, как мы ожидаем, т. е. во всех них реализован интерфейс руль- газ-тормоз. Это стандарт, которого "придерживается” большинство автомобилей.

Автомобили также реализуют "интерфейс" либо автоматической, либо ручной коробки передач. Все это не обязательно. Мы могли бы управлять колесами с помо­щью рычага и переключать передачи рулевым колесом. Это было бы непривычно, но в принципе возможно. Хуже всего было бы, если бы часть автомобилей управля­лось с помощью рычага, а другая часть — с помощью руля. Тогда все бы запутались. Так что здорово, что существуют стандарты, в соответствии с которыми автомобили ведут себя предсказуемо.

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

Interface FileType

{

Int read () ;

Void write (int data) ;

}

Любой класс, реализующий этот интерфейс, гарантированно поддерживает ме­тоды Read И Write, Определенные в интерфейсе FiieType. Неважно, записывает ли класс информацию в файл, на FTP-сервер, в память или на обои, наклеенные на стенку. Во всех случаях мы знаем, как с помощью этого класса читать и записывать целые значения, независимо от деталей реализации класса. (Согласен, то, что свя­зано с обоями, понять трудновато, но я думаю, что до вас дошла моя мысль.)

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

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

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

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

Программисты, знакомые с языком C++, могут рассматривать интер­фейсы как классы, содержащие только виртуальные абстрактные методы. Вы можете прочитать об инструментах JBuiIder, позволяющих автоматически реализовать интерфей­Сы, в главе 7, "Использование редактора".

Резюме

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

Чарли Калверт

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *