
Томас М., Пател П. - Секреты программирования для Internet на Java / Секреты программирования для Internet на Java
.pdf
СОВЕТ Если вы явно не определили метод или переменную, компилятор считает, что вы хотите, чтобы они были определены с модификатором protected. Тем не менее, если потом вы решите поместить их в собственный пакет, элементы, которые до тех пор были доступны из классов того же рабочего каталога, больше не будут доступны. В таком случае всегда лучше явно определить элементы класса.
Модификатор доступа private protected
Модификатор private protected предоставляет меньше доступа, чем модификатор protected, но больше, чем модификатор private. Элемент, определенный с модификатором private protected, доступен только из подклассов некоего класса. Если другие модификаторы, которые мы использовали, соответствуют концепции затенения данных, то модификатор private protected наиболее важен при рассмотрении наследования классов.
Допустим, в некоем классе мы определяем переменную или метод с модификатором private. Если мы создаем подкласс в этом классе, этот подкласс не может обращаться к элементам, определенным с модификатором private, если суперкласс не входит в подкласс. Как будет объяснено в следующем разделе, часто бывает удобно разработать базовый класс, задача которого - просто существовать и содержать в себе несколько подклассов. В этом случае гораздо удобнее использовать не модификатор private, а модификатор private protected, чтобы подклассам не приходилось выполнять всю реальную работу через методы суперкласса, определенные с модификатором public.
Как работает наследование
Мы бегло ознакомились с тем, что скрывается под словами "объектная ориентация Java". Надеемся, что теперь вы уверенно владеете двумя ключевыми понятиями объектной ориентации - затенением данных и инкапсуляцией, и знаете, как использовать их в Java. Мы познакомили вас также с понятием наследования. Давайте теперь более глубоко рассмотрим механизм наследования. В данном разделе будет показано, как можно улучшить качество программирования за счет использования наследования при формировании иерархии классов. В Java существуют абстрактные классы и методы, которые помогут нам в структурировании иерархий классов.
Структурирование иерархий классов
В начале этой главы, при обсуждении возможности повторного использования, было показано, что наследование позволяет надстраивать уже написанные классы. Но наш пример продемонстрировал только одну часть повторного использования программы. Повторное использование - лишь одно из преимуществ наследования. С помощью наследования мы можем гораздо разумнее расположить ключевые модули нашей программы.
Обратимся к примеру, использованному нами в главе 1, "World Wide Web и Java", при объяснении того, что такое объектная ориентация. Как вы, возможно, помните, мы привели простую задачу "пойди в магазин и купи молока" и показали, как сформулировать ее в терминах объектной ориентации. Рассмотрим один из компонентов этой задачи, а именно пакет молока.
Допустим, что мы программируем целую систему. Мы могли бы написать класс, описывающий молоко. Но существует несколько различных видов молока, например обезжиренное и молоко с добавлением шоколада. И даже если бы все виды молока объединились в одну единицу, эта единица была бы только одной в множестве молочных продуктов. Таким образом, мы могли бы создать иерархию классов, подобную той, что приведена на рис. 3-3.
www.books-shop.com

Рис. 3.3.
К счастью, это не просто упражнение в логическом мышлении. Java позволяет реализовать подкласс, а затем привести его к такому типу, чтобы он действовал как переменная суперкласса. Это очень ценно, если нас волнует только один общий аспект, определенный в верхней части иерархии классов, - например, скиснет ли наш молочный продукт на этой неделе. Допустим, наш класс dairyProduct (молочный продукт) содержит следующий метод:
public class dairyProduct { // переменные, конструкторы
public boolean sourThisWeek() {
// соответствующий текст программы
}
// другие методы
public void putOn Sale() {
// программа покупки молочного продукта в магазине
}
Вот тут-то и возникает необходимость приведения (casting). Если у нас уже есть переменная - например, lowfatMilk (обезжиренное молоко), - мы можем привести ее к переменной типа dairyProduct:
lowfatMilk M=new lowfatMilk(); dairyProduct D=M;
if (D.sourThisWeek()) { System.out.println("Не покупайте");}
В чем преимущество такого подхода? Скажем, директор магазина хочет выяснить, какие пакеты с молоком скиснут на этой неделе. Те, что могут скиснуть, будут пущены в продажу. Директор должен просто перенести все объекты lowfatMilk, Milk, Cheese и Yogurt в следующий метод:
public void dumpSourGoods(dairyGood d) { if (d.sourThisWeek()) {
d.putOnSale();}
}
Если бы для начала мы не построили иерархию классов, нам пришлось бы писать свой метод для каждого вида молочного продукта.
Абстрактные классы и методы
В предыдущем примере мы создали иерархию классов. Но наш класс dairyProduct содержит методы, у которых нет тела. Когда мы его написали, мы просто упомянули, что эти методы будут переопределены в подклассе. Однако, просмотрев нашу программу, трудно понять, что мы намереваемся это сделать. Для оказания помощи в этой ситуации в Java существует модификатор
www.books-shop.com
abstract.
При использовании модификатора abstract с методами все подклассы должны переопределить абстрактный метод. Вот как можно сделать абстрактные методы для нашего класса dairyProduct
public class dairyProduct { // переменные, конструкторы
public abstract boolean sourThisWeek(); // другие методы
public abstract void putOnSale();
}
Класс dairyProduct по-прежнему может быть реализован - просто теперь нельзя обратиться к абстрактным методам через объект класса dairyProduct. Однако мы можем также воспользоваться модификатором abstract для того, чтобы показать, что мы не хотим, чтобы объект был создан непосредственно:
public abstract myAbstractClass { // программа
}
Когда мы определяем класс как абстрактный, мы можем объединить в нем методы и переменные. Когда мы создаем в классе подкласс, он наследует все элементы абстрактного класса по тем же правилам наследования, что мы уже описали.
Полиморфизм и интерфейсы Java
Объясняя преимущества объектной ориентации Java, мы столкнулись с понятиями, которые легко можно объяснить на основе того, что мы уже знаем из главы 2, "Основы программирования на Java". Теперь введем понятие полиморфизма и остановимся на том, как структурные механизмы Java - интерфейсы - позволяют включать полиморфизм в программу.
Полиморфизм - это процесс, с помощью которого мы можем вызвать один и тот же метод на группе объектов, причем каждый объект будет реагировать на вызов метода по-своему. В нашем примере с dairyGoods мы уже имели дело с полиморфизмом. Например, методы putOnSale и sourThisWeek определены во всех классах иерархии. Мы можем вызывать эти методы на всех объектах - что мы и делали, когда выставили на продажу все продукты, которые скоро могут скиснуть, - и каждый класс определяет, как будут в действительности реагировать его реализации.
Однако полиморфизм - понятие в какой-то степени ограниченное. Мы можем быть уверены только в том, что классы одного экземпляра будут содержать все методы, определенные в суперклассе. Но часто бывает, что некоторые подклассы должны содержать методы, не содержащиеся во всей иерархии. Например, поскольку молоко и йогурт являются жидкими продуктами, нам могут потребоваться методы cleanUpSpill (мытье пролитого) на случай, если пакет упадет. Но глупо было бы определять для класса Cheese метод мытья пролитого сыра. Кроме того, в магазине могут пролиться и различные немолочные продукты.
Хорошо структурированная иерархия классов не решает эту задачу. Даже если у нас есть класс storeGood (хранение продукта), расположенный над всеми классами, определяющими продукты в нашем магазине, не имеет смысла определять метод cleanUpSpill в верхней части, потому что многие продукты в магазине не могут пролиться. Что нам нужно (и это есть в Java), так это способ определения набора методов, реализуемых некоторыми, но не всеми классами иерархии. Такая структура называется интерфейсом.
Начнем мы исследование интерфейсов с определения интерфейса для наших жидких продуктов, которые могут пролиться:
interface spillable {
public void cleanUpSpill(); public boolean hasBeenSpilled();
}
Как вы можете видеть, данные методы определяются аналогично тому, как мы определяли абстрактные методы. Разумеется, эти методы абстрактные - они должны быть определены внутри класса, реализующего интерфейс. Заметим, кроме того, что у нас нет ни переменных, ни конструкторов. Те и другие не разрешается использовать в интерфейсе, потому что интерфейс -
www.books-shop.com
это всего лишь набор абстрактных методов. Вот пример использования интерфейса для нашего класса Milk:
public class Milk extends dairyProduct implements Spillable {
//переменные, конструкторы public boolean hasBeenSpilled {
//соответствующая программа
}
public void cleanUpSpill {
// соответствующая программа
}
// другие методы
}
Ключевое слово implements показывает, что класс Milk определяет методы в интерфейсе Spillable (проливаемые продукты). Разумеется, если у нас есть экземпляр класса Milk, мы можем вызвать методы hasbeenSpilled (пролитый продукт) и cleanUpSpill. Преимущество подобных интерфейсов в том, что они, так же как и классы, относятся к типу данных. Хотя мы и не можем непосредственно их реализовать, мы можем представить их в виде переменных:
class Milk m+new Milk(); Spillable S=(Spillable)M; if (S.hasBeenSpilled())
{s.cleanUpSpill();}
Теперь мы можем через тип данных Spillable обратиться ко всем методам, имеющим дело с проливанием, и при этом нам не нужно будет определять все методы в базовом классе для всех продуктов в магазине - как жидких, так и твердых.
Кроме того, мы можем реализовать больше одного интерфейса в классе. Например, мы можем написать интерфейс Perishable (скоропортящиеся продукты), описывающий все продукты, которые могут испортиться. Наш класс Milk реализует оба интерфейса со следующим описанием класса:
public class Milk omplements Spillable, Perishable { // определение класса
}
На самом деле было бы лучше реализовать интерфейс Perishable на уровне класса dairyGoods, потому что все молочные продукты являются скоропортящимися. Но не стоит беспокоиться - подклассы наследуют интерфейсы экземпляров их суперклассов.
Обзор понятий и пример
В этой главе мы рассмотрели множество понятий. Вы узнали, почему техника объектного ориентирования полезна вообще, как определять и использовать объекты и применять в Java такие фундаментальные методы OOP, как наследование и совмещение. Для того чтобы показать, что могут делать объекты для самого языка, были введены массивы. Ниже приведены табл. 3-3, суммирующая все понятия объектного ориентирования, и пример, который все эти понятия использует.
Таблица 3-3. Понятия и терминология объектного ориентирования
Понятие |
Описание |
Класс |
Тип, определяющий некие данные и группу функций, действующую на |
|
этих данных. |
Объект, экземпляр, Переменная типа class, которая появляется после реализации класса.
реализация
Затенение данных Метод, позволяющий затенить переменную от других объектов. Затенение данных обычно облегчает процесс изменения внутренних структур данных.
Инкапсуляция Заключение функций и данных в одни пакет.
www.books-shop.com
Mодификаторы |
Операторы, описывающие, какие классы могут обращаться к |
доступа |
переменным или методам, определенным в классе. |
Реализация |
Создание объекта из класса. Реализация создает объект класса. |
Конструктор |
Раздел программы инициализации, вызываемый при реализации |
|
класса. |
Иерархия классов |
Многоуровневая диаграмма, показывающая взаимоотношения между |
|
классами. |
Наследование |
Создание нового класса расширением функций другого класса. |
Суперкласс |
Класс, унаследованный от другого класса. |
Подкласс |
Класс, наследующий от другого класса. |
Переопределение |
Переопределение методов подкласса, определенных в суперклассе. |
метода |
|
Чтобы объединить все эти понятия в программе, мы создадим небольшую иерархию классов. Следующие группы объектов реализуют низкоуровневую графическую систему. Допустим, наша клиентка попросила нас написать программу рисования. Она хотела бы иметь возможность перемещать элементы рисунка как самостоятельные объекты. Первая демонстрационная версия будет включать примитивные формы, но окончательный проект может содержать множество сложных форм и растровых изображений. Если мы сможем сделать демо-версию к началу следующей недели, мы заключим контракт; в противном случае нам придется еще шесть месяцев корпеть над строками технического сопровождения. Ужасная перспектива, так что давайте поскорее сделаем работающую демо-версию.
Тот факт, что мы не знаем все формы, которые мы должны реализовать, усложняет нашу задачу. Нам придется применить наши знания методов OOP, чтобы сделать программу возможно более открытой. Одно из самых мощных наших орудий - наследование. Если мы правильно спроектируем иерархию объектов, у нас будет основа, в которую можно будет добавлять любое количество новых форм.
Помните про интерфейс? Он используется для того, чтобы группа объектов могла подчиняться стандартному набору правил. Эта возможность понадобится нам для создания программы рисования. Каждая форма должна будет иметь дело с несколькими важными подпрограммами. Нам нужно, чтобы каждая форма могла быть изображена на экране, чтобы это изображение можно было спрятать и переместить в другое место. Для такого основного набора операций мы можем написать простую программу рисования. Назовем наш интерфейс Shape (форма). Вот определение Shape:
interface Shape {
public void show(); public void hide();
}
Чтобы добавить в код новую форму, программа рисования должна будет выполнить только эти подпрограммы. С остальными подпрограммами будут иметь дело другие объекты иерархии. Следующий объект будет следить за местоположением формы. Любой текст программы, которым мы захотим описать формы, будет храниться в этом классе. Назовем этот класс BaseShape (базовая форма); он определен ниже. Заметим, что этот класс абстрактный и содержит абстрактные методы:
abstract class BaseShape { protected int x,y;
public void setPos(int newX, int newY) { x = newX;
y = newY;
}
}
Теперь у нас есть общий интерфейс для каждой формы и базовый класс, откуда можно наследовать. Любой метод, который понадобится реализовать во всех формах, будет помещен в интерфейс. Общая часть программы для форм помещается в класс BaseShape. Последняя часть программы предназначена для реализации индивидуальных форм и небольшой демо-версии.
Следующий текст показывает, как реализуются некоторые формы, а именно прямоугольник и круг. Для каждой формы могут понадобиться дополнительные элементы данных и методы для
www.books-shop.com
реализации данного конкретного рисунка. Чтобы воспользоваться удобным методом затенения данных, определим эти переменные и методы с модификатором private:
class Rectangle extends BaseShape implements Shape { private int len, width;
Rectangle(int x, int y, int Len, int Width) { setPos(x,y);
len = Len; width = Width;
}
public void show() {
System.out.println("Прямоугольник(" + x + "," + y + ")"); System.out.println("Длина=" + len + ", Ширина=" + width);
}
public void hide() {}
}
class Circle extends BaseShape implements Shape { private int radius;
Circle(int x1, int y1, int Radius) { setPos(x1,y1);
radius = Radius;
}
public void show() {
System.out.println("Круг(" + x + "," + y + ")"); System.out.println("Радиус=" + radius);
}
public void hide() {}
}
Последнее, что нам осталось, - сама программа рисования. Представьте себе, как долго вы могли бы мучиться с такой программой. Поскольку мы хотим хранить каждую форму отдельно, нам нужен способ хранения индивидуальных компонентов. Комбинация этих форм создает некий рисунок. Преимущество нашего подхода состоит в том, что мы легко можем перемещать или копировать элементы рисунка в другие места. Для этого нам нужен способ хранения элементов рисунка.
Здесь возникает следующая проблема. Какой тип структуры данных можно использовать, чтобы хранить множество объектов различных типов? Самым простым типом является массив. Массивы в Java позволяют хранить любой тип данных. Данные могут быть простого типа, например целые, более сложного типа, например объекты, или, как в нашем случае, интерфейсы, то есть определенного программистом типом. Мы определяем массив, который будет хранить объекты, реализующие интерфейс shape. Это позволит нам вызывать любой из определенных методов форм, не зная точно, какого типа этот объект. Мы можем продолжать создавать новые формы, не меняя нашей программы рисования. Это огромное достижение объектно-ориентированных языков!
class testShapes {
public static void main(String ARGV[]) { Shape shapeList[] = new Shape[2]; int i;
shapeList[0] = new Rectangle(0,0,5,5); shapeList[1] = new Circle(7,7,4); for(i=0, i<<2, i++) {
shapeList[i].show();
}
}
}
Итак, вот она - простая программа, выполняющая основную работу нашей программы рисования. Добавим к ней графический раздел программы и получим удобную в употреблении и открытую для добавлений программу рисования. Когда наша клиентка попросит внести изменения в начальную программу, мы будем к этому готовы. Созданный каркас станет основой для реализации постоянно улучшающейся программы рисования. Хватит заниматься техническим сопровождением - у нас контракт!
www.books-shop.com
Что дальше?
Мы надеемся, что теперь у вас сложилось четкое понимание ключевых понятий объектной ориентации и того, как они используются в Java. В следующей главе мы потратим некоторое время на описание синтаксиса языка. Хотя отчасти это описание будет носить обзорный характер, некоторые разделы будут совершенно новыми для вас. Надеемся, что к тому моменту, когда мы перейдем к самой сути - написанию применений и апплетов Java, - вы станете хорошо разбираться в основных понятиях языка Java и будете готовы приступить к настоящей работе.
www.books-shop.com

Глава 4
Синтаксис и семантика
Идентификаторы и использование стандарта Unicode Комментарии Ключевые слова Типы данных
Примитивные типы данных Целые числа Числа с плавающей точкой Символы
Тип boolean
Преобразование примитивных типов данных Преобразование значений с плавающей точкой в целочисленные значения
Преобразование числа с плавающей точкой двойной разрядности к обычной разрядности Преобразования типа boolean
Объявление переменных Область действия
Правила именования переменных Знаки операций
Знаки операций с числовыми аргументами Знаки операций над объектами Операции над строками
Пакеты
Импорт
Классы
Конструкторы
Деструкторы Модификаторы классов
Модификаторы объявления переменных Модификаторы методов Совмещение методов
Преобразование типов ссылочных переменных Интерфейсы Массивы
Создание массивов Инициализация массивов Доступ к массивам
Передача управления Оператор if-else
Операторы while и do-while
Оператор for
Операторы break и continue
Оператор return Оператор switch
Исключения
Язык Java в значительной своей части основан на языках C и C++, поэтому тот, кто хорошо знает эти языки, может считать эту главу почти что повторением пройденного. Разработчики Java поставили перед собой очевидную цель: создать язык, максимально похожий на C/C++, но который можно было бы эффективно использовать в программировании приложений для сети Интернет. Однако, чтобы достичь этой цели, им пришлось восполнить серьезнейшие пробелы C/C++ в таких областях, как безопасность, переносимость и удобство обслуживания программ. Кроме того, для создания Интернет-приложений потребовалось ввести в язык Java многопотоковость и обработку исключительных ситуаций. Таким образом, большинство отличий языка Java от языков C и C++ подпадают под одну из вышеперечисленных категорий.
Большинство информации, приведенной в этой главе, извлечено из официального документа под названием Java Language Specification (Спецификация языка Java) версии 1.0. Развитие языка продолжается, и поэтому вы наверняка будете сталкиваться с изменениями в будущих версиях Java. К примеру, в языке в его теперешнем состоянии присутствует несколько ключевых слов, значение которых не определено. Фирма Sun уже упоминала некоторые из возможных
www.books-shop.com

изменений и дополнений в будущих версиях языка. Мы будем выносить информацию об изменениях языка по мере их появления на страницу Online Companion в World Wide Web.
Основное назначение этой главы - служить справочником, к которому вы сможете постоянно обращаться в своей практической работе. Однако здесь вы найдете и кое-какую общую информацию о языке. Нам бы хотелось, чтобы вы по крайней мере просмотрели эту главу, прежде чем переходить к изучению остальных глав книги. Особое внимание следует уделить разделам, посвященным массивам и исключительным ситуациям. Дело в том, что работа с массивами и обработка исключительных ситуаций в языке Java организованы не так, как в других языках программирования. В частности, понятие исключительных ситуаций является одним из ключевых понятий этого языка, и значительная часть материала всей книги имеет отношение к этому понятию.
Вэтой главе мы изучим синтаксис языка Java для следующих элементов языка:
•идентификаторы и использование стандарта Unicode,
•ключевые слова,
•типы данных,
•примитивные типы данных,
•преобразование примитивных типов данных,
•объявление переменных,
•знаки операций,
•пакеты,
•классы,
•преобразование ссылочных типов данных,
•интерфейсы,
•массивы,
•передача управления,
•исключения.
СОВЕТ Информацию о последних изменениях в стандарте языка Java вы всегда сможете найти на странице Online Companion по адресу http://www.vmedia.com/java.html.
Идентификаторы и использование стандарта Unicode
Идентификаторами называют имена, присваиваемые различным элементам программы. Любой объект, создаваемый в Java-программе, - переменная, метод или класс - имеет свое имя, которое представляет собой не что иное, как идентификатор. Идентификаторы в языке Java строятся из символов стандарта Unicode. "Что же такое Unicode? - спросите вы. - Еще один стандарт, который мне придется учить?" Вовсе нет! Весьма вероятно, что после того, как вы освоите материал этой главы, вам больше никогда в жизни не придется встречаться со стандартом Unicode.
Разработчики Java поставили перед собой цель сделать язык максимально переносимым, то есть таким, чтобы его могли с равным успехом использовать программисты, работающие не только на разных компьютерных платформах, но и живущие в разных странах и говорящие на разных языках. Поддержка иностранных языков стала актуальной в последние годы, когда многие компьютерные компании двинулись на завоевание рынков сбыта других стран и континентов. В настоящее время большинство компьютерных программ пишется с использованием английского языка, поэтому программисты в странах, где этот язык является иностранным, вынуждены фактически работать на чужом языке. Изучение компьютеров и без того дается многим людям с большим трудом. Зачем же еще больше усложнять жизнь? Стандарт Unicode и был разработан именно для того, чтобы помочь людям в других странах работать с компьютерами.
Стандарт Unicode был разработан организацией под названием Консорциум Unicode (Unicode Consortium), и его первая версия была опубликована в 1990 г. Этот стандарт унифицирует кодировку символов алфавитов большинства современных и древних языков. Каждый символ по стандарту Unicode кодируется 16 битами. Большинство пользователей работают с символами, закодированными по стандарту ASCII, в соответствии с которым каждый символ кодируется 7 битами. Увеличение количества битов на символ в стандарте Unicode позволяет расширить набор кодируемых символов, добавив к нему буквы других алфавитов и буквы с диакритическими значками, которые используются во многих языках. Все Java-программы кодируются с использованием Unicode, и все строки и одиночные символы, используемые в программах, хранятся в памяти в виде 16-битовых кодов.
Значит ли это, что вам придется учить еще одну кодировку символов? Конечно, нет. Более
www.books-shop.com

того, использование Unicode скорее всего вообще никак не повлияет на вашу практическую работу как программиста. Если вы не используете в своих программах никаких символов, выходящих за пределы латинского алфавита, то вы можете вообще не задумываться об этом и продолжать писать программы так же, как делали это всю жизнь. Преобразованием вашего ASCII-файла в файл, закодированный по стандарту Unicode, займется компилятор Java, так что исходные тексты программ вам не придется хранить в каком-то специальном формате.
Таким образом, решение фирмы Sun использовать стандарт Unicode не окажет большого влияния на жизнь программистов-практиков. Нужно лишь помнить, что определенные типы данных занимают теперь больше места в памяти - а именно, все строки и одиночные символы увеличиваются в размерах в два раза. Конечно, на первый взгляд это может показаться недостатком языка. Однако вспомните, что при разработке Java главной целью было вовсе не экономное расходование памяти, а эффективное программирование для Интернет и возможность создания переносимых программ. То, что эти главные задачи успешно решены, позволяет мириться с несколько неэффективным расходом памяти для символьных значений. Вполне возможно, что, когда вам понадобится локализовать свою программу для использования в других странах, вы возблагодарите судьбу за то, что программисты фирмы Sun приняли в свое время столь дальновидное решение.
СОВЕТ Если вам понадобится узнать подробнее о стандарте Unicode, загляните на страницу по адресу http://unicode.org. Там вы найдете информацию о стандарте, сведения о том, как заказать бумажную копию стандарта Unicode, и узнаете, что нужно для того, чтобы стать членом Консорциума Unicode.
Комментарии
Java поддерживает все способы оформления комментариев, принятые в C/C++, и добавляет к ним еще один новый способ, ориентированный на автоматизированное документирование программного кода. Разумеется, какой бы стиль оформления комментариев вы ни использовали, на содержательную сторону программ это никак не влияет: компилятор игнорирует все возможные виды комментариев.
Комментарии в стиле C/C++ можно оформлять одним из следующих способов: // текст
Весь текст, заключенный между этими сочетаниями символов, будет проигнорирован. Такой комментарий может распространяться на несколько строк.
// текст Весь текст, следующий после // до конца строки, игнорируется.
В языке Java добавлен третий вариант оформления комментариев, используемый для автоматического документирования программ с помощью утилиты javadoc. Эта утилита, входящая в JDK, создает Web-страницу с описанием вашего кода; основой текста на этой странице как раз и будут комментарии в тексте программы, оформленные таким образом. Эти комментарии имеют следующий вид:
/** текст */
Текст в этом комментарии относится к переменной или методу, расположенному сразу после комментария.
Однако это еще не все. Авторы любого языка, а особенно такого, где допустимо несколько способов оформления комментариев, должны явным образом задать правила интерпретации для некоторых особых ситуаций, как, например, вложенных комментариев. В этом отношении между разными языками, включая Java, наблюдаются серьезные разногласия. В Java эти правила формулируются так:
•Комментарии не могут вкладываться друг в друга.
•Комментарии не могут быть частью строк или символьных констант.
•Сочетания символов /* и */ не имеют никакого специального значения в комментариях, отбитых символами //.
•Сочетание символов // не имеет никакого специального значения в комментариях, заключенных между /* и */.
Чтобы пояснить действие этих правил, достаточно одного примера. Следующая строка будет интерпретироваться как один вполне законный комментарий:
/* Это обычный комментарий, содержащий сколько угодно //, /*, /**. Чтобы закончить его, нужно написать */
Ⱦɚɧɧɚɹ ɜɟɪɫɢɹ ɤɧɢɝɢ ɜɵɩɭɳɟɧɚ ɷɥɟɤɬɪɨɧɧɵɦ ɢɡɞɚɬɟɥɶɫɬɜɨɦ %RRNV VKRS Ɋɚɫɩɪɨɫɬɪɚɧɟɧɢɟ ɩɪɨɞɚɠɚ ɩɟɪɟɡɚɩɢɫɶ ɞɚɧɧɨɣ ɤɧɢɝɢ ɢɥɢ ɟɟ ɱɚɫɬɟɣ ɁȺɉɊȿɓȿɇɕ Ɉ ɜɫɟɯ ɧɚɪɭɲɟɧɢɹɯ ɩɪɨɫɶɛɚ ɫɨɨɛɳɚɬɶ ɩɨ ɚɞɪɟɫɭ piracy@books-shop.com