Главная » Java, Web » Интерфейсы. Вложенные классы java

0

В этой части дан краткий обзор понятия интерфейсов и вложенных классов.

Интерфейсы

В некоторых языках программирования, например, в языке С++, допускается иметь два и более суперкласса. Это есть множественное наследование. На рис. П4.10 класс е имеет два класса (а и в), которые являются прямыми суперклассами для этого класса, а класс f имеет три суперкласса.

Рис. П4.10. Множественное наследование

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

В Java интерфейс (interface) — это зарезервированное слово, оно несет определенный смысл. Интерфейс, определенный с помощью специального слова interface, состоит из набора функций, с которыми не связывается никакая конкретная имплементация. Класс может имплементировать интерфейс, для этого он должен имплементировать каждую функцию, описанную в интерфейсе. Приведем пример простого интерфейса Java: public interface Drawable {

public void draw(Graphics g) ;

Все выглядит похожим на описание класса. Однако имплементация метода draw () отсутствует. Пример имплементации этого интерфейса приведен далее:

class Line implements Drawable { public void draw(Graphics g) { // функции (рисование линии)

// прочие методы и переменные

Каждый класс, имплементирующий интерфейс Drawable, описывает метод draw (). Каждый объект, созданный на основе этого класса, содержит метод draw (). Говорят, что объект имплементирует интерфейс, если этот объект принадлежит классу, который ипмлементирует интерфейс. Помимо того, что класс должен имплементировать все методы интерфейса, необходимо явно указать, что класс имплементирует данный интерфейс (например, написать implements Drawable). Класс может иметь только один суперкласс, но он может имплементировать несколько интерфейсов.

j Пример

class FilledCircle extends Circle implements Drawable, Finable {

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

! Пример (Drawable — интерфейс)                                                                                                   I

Drawable figure; // Объявляет переменную типа Drawable.

// Она может содержать ссылку на любой объект, // имплементирующий интерфейс Drawable. figure = new Line(); // figure ссылается на объект класса Line figure.draw(g);       // вызывает draw() класса Line

figure = new FilledCircle(); // сейчас figure ссылается на объект

// класса FilledCircle figure.draw(g); // вызывает метод draw() из класса FilledCircle

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

Вложенные классы

Вложенный ютсс — это класс, описание которого находится внутри описания другого класса. Внутренние вложенные классы могут иметь собственное имя или быть анонимными. Именованный внутренний класс выглядит точно так же, как и любой другой обычный класс, единственное его отличие состоит в том, что он определен внутри другого класса. Как и прочие элементы класса, внутренний класс может быть как статическим, так и нет. Статический вложенный класс является частью статической структуры основного класса. Этот класс может использоваться внутри основного класса для создания объектов этого класса. Если внутренний класс не был объявлен как private, то этот класс также может использоваться и извне. При обращении к классу извне имя этого класса должно содержать часть, указывающую на класс, частью которого он является. Если, предположим, класс wireFrameModei представляет набор линий в трехмерном пространстве и содержит статический вложенный класс Line, тогда доступ к классу Line может быть осуществлен при помощи WireFrameModei.Line. В этом нет ничего особенного или нового. Описание класса WireFrameModei может иметь следующий вид:

public class WireFrameModei {

// прочие члены класса WireFrameModei static public class Line {

11 представляет линию от точки (xl,yl,zl)

// к точке (х2,у2,z2) в трехмерном пространстве

double xl, yl, zl;

double x2, y2, z2;

}

… // прочие члены класса WireFrameModel

}

Внутри класса wireframeModei объект типа Line может быть создан с применением конструктора new Line(). Вне класса используется new wire- FrameModei. Line (). Статический вложенный класс имеет полный доступ ко всем членам содержащего его класса, в том числе к членам, объявленным как privat. Этот факт, в частности, может служить причиной для использования вложенных классов. С помощью вложеных классов можно организовать доступ к защищенным членам класса, т. е. к тем членам, которые непосредственно не доступны для внешних классов.

Если мы используем написанный выше код и скомпилируем его, то получим два класса. Это произойдет несмотря на то, что класс Line определен внутри другого класса. Класс Line будет сохранен в виде отдельного файла Wire Frame FvlodclS Line.class.

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

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

Чтобы создать объект, относящийся к классу, который вложен в другой класс, необходимо сначала создать объект, относящийся к основному классу, в который вложен второй класс. Объект вложенного класса навсегда связан с объектом основного класса, он имеет полный доступ к членам содержащего его класса. Рассмотрим класс PokerGame, сордержащий вложенные классы:

class PokerGame { // Игра в покер.

class Player { // Представляет одного игрока.

}

private Deck deck;     // Карты.

private int pot;       // Количество денег.

}

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

В некоторых ситуациях можно было бы создать вложенный класс, который затем используется лишь однажды и только в одной единственной строке программы. Возникает вопрос, а стоит ли создавать такой класс? Конечно, его можно было бы создать, но для таких ситуаций мы имеем возможность воспользоваться анонимными классами. Анонимный класс создается с помощью разновидности оператора new по следующей схеме: new superclass-or-interface () { methods-and-variables

}

Конструктор определяет новый класс без указания имени, одновременно создавая объект этого класса. Такая конструкция может быть использована в составе любой инструкции, где можно использовать оператор new. Эта инструкция сообщает, что необходимо создать новый объект класса (или интерфейса) superciass-or-interface с дополнительными методами и переменными methods-and-variables. При помощи такого способа можно создавать новый объект в любом месте программы.

Анонимные методы часто используются для обработки событий при создании графического интерфейса пользователя. Рассмотрим интерфейс Drawabie (ранее мы о нем уже говорили). Предположим, что нам нужен красный квадрат со стороной 100 пикселов. Вместо того чтобы создавать отдельный самостоятельный класс, который в дальнейшем будет использован для создания объекта квадарта, мы используем анонимный класс и создаем объект одной строкой:

Drawable redSquare = new Drawable() { void draw(Graphics g) { g.setColor(Color.red) ;

g.fillRect(10,10,100,100); }

};

Точка с запятой в конце не является частью определения класса, она является частью инструкции, с помощью которой мы объявляем переменную. При компиляции анонимные классы сохраняются в виде самостоятельных файлов. Если имя основного класса Mainciass, то анонимные классы будут сохранены В файлах С именами MainClass$l. class, MainClass$2. class, MainClass$3.class И Т. Д.

Модификаторы доступа

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

При создании пакетов все будет несколько иначе. Пакет содержит набор классов, которые имеют друг к другу какое-либо отношение. Некоторые из этих классов могут быть общедоступны (public). Другие классы используются только внутри пакета и не должны быть объявлены как public. Любая переменная или функция, которая является членом класса, может быть также объявлена общедоступной (public), что означает, что она будет доступна из любого места. Ее можно объявить закрытой (private), тогда она будет доступна только из кода содержащего ее класса. Если у переменной или функции не указан явно модификатор доступа, то переменная будет доступна из любого класса, входящего в тот же самый пакет, что и класс, в котором расположена переменная или функция. Существует еще один модификатор доступа — protected. При помощи этого модификатора описывается функция или переменная, которая будет доступна только из таких классов, которые являются подклассами для того класса, где описана эта переменная или функция. Этот модификатор накладывает больше ограничений, чем модификатор public, но эти ограничения менее строги, чем те, что будут наложены в случае использования модификатора private. Те классы, которые разрабатываются специально для того, чтобы на их основе создавались подклассы, часто имеют в качестве своих членов имена, описанные при помощи модификатора protected.

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

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

Предположим, что мы хотим создать класс, описывающий игральные кости, класс PairOfDice, и этот класс использует другой класс Random, который бросает кости, к которому обращается объект PairOfDice. Может существовать несколько объектов костей. Для каждого такого объекта вовсе не обязательно иметь свой собственный объект Random. Более того, было бы даже неправильным, если бы у каждой пары костей был свой объект Random. Наиболее удобным будет такое решение, когда один и тот же статический класс Random будет использоваться всеми объектами типа PairOfDice.

Пример

class PairOfDice {

private static Random randGen = new Random(); // предполагается, что импортирован j ava.ut i1.Random public int diel; // первая кость

public int die2; 11 вторая кость public PairOfDice() { // Конструктор. Создает две кости 11 со случайными значениями. roll () ;

public void roll() { // бросаем кости // случайные значения от 1 до 6 diel = randGen.nextInt(6) + 1; die2 = randGen.nextInt(6) + 1;

В качестве второго примера перепишем класс student. Для каждого студента укажем идентификатор id и создадим статическую переменную next Unique id. Для каждого экземпляра класса stydent создается собственный идентификатор id, но в то же время существует лишь одна общая переменная nextUniqueid.

Класс student

public class Student {

private String name; // имя студента private int ID; // идентификатор студента

public double testl, test2, test3; // оценки за три теста private static int nextUniquelD = 0; // запоминаем следующий идентификатор Student(String theName) {

// конструктор объекта студента; // задается имя студента, // присваивается уникальный // идентификатор студента name = theName; nextUniqueID++; ID = nextUniquelD;

}

public String getNameO {

// Метод доступа для чтения значения private

// переменной экземпляра класса. return name;

}

public int getID() {

// Метод для чтения значения переменной ID. return ID;

}

public double getAverageO { // вычисление средней оценки return (testl + test2 + test3) / 3;

}

}

Контрольные вопросы

1.    В объектно-ориентированном программировании используются классы и объекты. Что такое классы и что такое объекты?

Ответ. В программно-ориентированном подходе класс представляет собой шаблон, по которому создается объект (мы имеем в виду нестатические элементы класса). Объект — это набор данных и способов поведения, который представляет ту или иную сущность (абстрактную или конкретную). Класс определяет строение и поведение всех объектов определенного типа.

2.    Что обозначает специальное значение null и зачем оно нужно?

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

3.    Что такое конструктор? Каково назначение конструктора в классе?

Ответ. Конструктор — это специальная функция в классе. Имя конструктора должно совпадать с именем класса. Конструктор не возвращает никакого значения, в том числе значения void. Конструктор вызывается с применением оператора new, который создает новый объект. Назначение конструктора — инициализация новых объектов.

4.     В этом задании создайте простой класс, который будет содержать счетчик (проходит ряд 0, 1, 2, 3, 4, …). Класс назовем counter. В классе будет содержаться одна переменная private для счетчика. Класс будет иметь два метода: метод increment о (увеличивает значение счетчика на 1) и метод getvaiue () (возвращает текущее значение счетчика). Создайте описание класса counter.

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

public class Counter {

// Объект этого класса представляет собой счетчик // который считает, начиная с 0. private int value =0; // текущее значение счетчика

public void increment() {

// увеличение значения счетчика

value++; }

public int getValue() {

// возвращает текущее значение счетчика

return value; }

}

5. В этом задании используется класс из предыдущего вопроса. Фрагмент программы производит бросание монетки 100 раз. Используйте два объекта типа Counter, объекты headCount и tailCount. Эти объекты производят подсчет числа выпаданий решки и орла, соответственно. Заполните пропущенные места в программе.

Counter headCount, tailCount; tailCount = new Counter(); headCount = new Counter();

for (int flip = 0; flip < 100; flip++) {

if (Math.random() <0.5) // шанс выпадения 50 на 50     ; // считаем решки

else

________________________________  ; // считаем орлы

}

System, out.println ("Vypalo " + _________________  + " reshek. ") ;

System, out. println ("Vypalo " + ________________  + " orlov. ") ;

Ответ. Переменная headCount — это переменная типа counter. Все, что нам остается сделать, это обратиться к методам headCount. increment () и headCount. getValue (). Вызов метода headCount.increment () увеличивает

значение счетчика на единицу. Метод headCount.getValue() служит для чтения текущего значения счетчика:

Counter headCount, tailCount; tailCount = new Counter(); headCount = new Counter(); for (int flip = 0; flip < 100; flip++) { if (Math.random() < 0.5)

headCount.increment() ; tailCount.increment() ;

}

System.out.println(("Vypalo " + headCount.getValue() + " reshek."); System.out.println(("Vyaplo " + tailCount.getValue() + " orlov.");

Ниже приводится код, содержащийся в файле TextlO.java. Класс Textio используется в примерах настоящего приложения и в главах книги.

Файл TextlO.java

import java.io.*; public class TextlO {

j j                             ВвОД/ВЫВОД

// Методы для работы с примитивными типами и типом String. // Вывод на консоль без лишних пробелов. // Вещественные значения выводятся округленными, // при этом максимальное количество знаков будет 10 или 11. // Чтобы вывести число с сохранением максимальной точности, // следует использовать метод TextlO.put(String.valueOf(x)).

public static void put(int x)    { put(x,0); }

// Прим.: поддерживаются типы byte и short! public static void put(long x) { put(x,0); } public static void put(double x) { put(x,0); }

// Поддерживается тип float. public static void put(char x) { put(x,0); } public static void put(boolean x) { put(x,0); } public static void put(String x) { put(x, 0) ; }

// Методы для записи примитивных типов и типа String, // для вывода их на консоль с последующим символом перевода каретки // без лишних символов пробелов.

public static void putln (int x)    { put(x,0); newLine();  }

// Поддерживаются типы byte и short.

public static void putln(long x)    { put(x,0); newLine();  }

public static void putln(double x) { put(x,0); newLine(); }

// Поддерживается тип float.

public static void putln(char x)    { put(x,0); newLine();  }

public static void putln(boolean x) { put(x,0); newLine();  }

public static void putln(String x) { put(x,0); newLine(); }

// Методы для вывода примитивных типов и типа String на консоль // с минимальной шириной, заданной в качестве значения w, // символом перевода строки. Если ширина строки вывода // оказывается меньше w символов, // то она спереди заполняется пробелами.

public static void putln(int x, int w)    { put(x,w); newLine();   }

// Поддерживаются типы byte и short.

public static void putln(long x, int w) { put(x,w);  newLine(); }

public static void putln (double x, int w) { put(x,w); newLine();   }

// Поддерживается тип float.

public static void putln(char x, int w) { put(x,w);  newLine(); }

public static void putln(boolean x, int w) { put(x,w); newLine();   }

public static void putln(String x, int w) { put(x,w); newLine();   }

// Методы для вывода символа возврата каретки.

public static void putln() { newLine(); }

// Методы вывода примитивных типов и типа String на консоль

// с минимальной шириной, заданной в качестве значения переменной w.

public static void put(int x, int w)

{

dumpString(String.valueOf(x), w);

// Поддерживаются типы byte и short. public static void put(long x, int w)

dumpString(String.vaiueOf(x), w);

public static void put(double x, int w)

dumpString(realToString(x), w);

// Поддерживается тип float. public static void put(char x, int w)

dumpString(String.vaiueOf(x), w);

public static void put(boolean x, int w)

dumpString(String.vaiueOf(x), w);

public static void put(String x, int w)

dumpString(x, w);

// Методы чтения примитивных типов, а также типов "words" и "lines". // Методы "getln…" игнорируют лишние введенные символы вплоть //до символа возврата каретки (включая его). // Слово "word" читается с помощью метода getlnWordO //и представляет собой последовательность символов (не пробелов). // Строка "line" читается с помощью методов getInString() и getln() //и состоит из всех символов до символа CR;

// Символ CR (возврат каретки) не возвращается этими методами, //он читается и затем игнорируется.

// Все методы игнорируют символы пробелов в конце строки //и символ перевода каретки и ищут следующий символ, отличный от // пробела. Исключение составляют методы getAnyChar(), peek(). // Метод getln() может возвратить пустую строку, // методы getChar() и getlnChar() могут возвратить // пробел и перевод строки (‘\п’).

// Метод peek() позволяет найти следующий символ в потоке ввода, //не удаляя его из потока.

//В качестве допустимых логических значений могут быть использованы // следующие значения типа "words": true, false, t, f, yes, // no, у, n, 0 или 1; допускаются прописные буквы. // Методы не допускают появление ошибок. // Если обнаруживается ошибка,

// то методы предлагают пользователю повторить ввод. //============ Список методов =========================

//           getByte()     getlnByte() getShort()       getlnShort()

//           getInt()      getlnlnt()    getLong()     getlnLong()

//           getFloat()    getlnFloat() getDouble() getlnDouble()

//           getChar()     getlnChar() peek()           getAnyChar()

//           getWord()     getlnWord() getIn()          getString()

/ /          get InSt r ing ()

//

// (Метод getInString эквивалентен методу getln consistency.) public static byte getlnByte()

{ byte x=getByte();      emptyBuffer(); return x; }

public static short getlnShort ()

{ short x=getShort();    emptyBuffer(); return x; }

public static int getlnlnt ()

{ int x=getlnt();        emptyBuffer(); return x; }

public static long getlnLong()

{ long x=getLong();      emptyBuffer(); return x; }

public static float getlnFloat()

{ float x=getFloat();    emptyBuffer(); return x; }

public static double getlnDouble()

{ double x=getDouble(); emptyBuffer(); return x; } public static char getlnChar()

{ char x=getChar();      emptyBuffer(); return x; }

public static boolean getlnBoolean()

{ boolean x=getBoolean(); emptyBuffer(); return x; } public static String getlnWord ()

{ String x=getWord();    emptyBuffer(); return x; }

public static String getlnString() { return getln(); } // same as getln () public static String getln() {

StringBuffer s = new StringBuffer(100);

char ch = readChar(); while (ch != ‘\n’) { s.append(ch); ch = readChar();

}

return s.toString();

}

public static byte getByteO { return (byte)readlnteger(-128l,127L); } public static short getShort () { return (short)readlnteger(-32768L,32767L); } public static int getInt()

{ return (int)readlnteger((long)Integer.MIN_VALUE,

(long)Integer.MAX_VALUE);

}

public static long getLong()

{ return readlnteger(Long.MIN_VALUE, Long.MAX_VALUE); } public static char getAnyChar() { return readChar(); } public static char peek() { return lookChar(); }

public static char getChar() {

// пропускаем пробелы и символы, затем возвращаем следующий символ char ch = lookChar();

while (ch == ‘ ‘ || ch == ‘\n’) {

readChar(); if (ch == ‘\n’)

dumpString("? ", 0) ; ch = lookChar();

}

return readChar();

}

public static float getFloat() {

float x = 0.OF; while (true) {

String str = readRealString(); if (str.equals("")) {

errorMessage ("Illegal floating point input.",

"Real number in the range " + Float.MIN_VALUE + " to " + Float.MAX_VALUE);

}

else {

Float f = null;

try { f = Float.valueOf(str); } catch (NumberFormatException e) {

errorMessage("Illegal floating point input.", "Real number in the range " + Float.MIN_VALUE + " to " + Float.MAX_VALUE);

continue;

}

if (f.islnfinite()) {

errorMessage("Floating point input outside of legal range.", "Real number in the range " + Float.MIN_VALUE + " to " + Float.MAX_VALUE);

continue;

}

x = f.floatValue(); break;

}

}

return x;

}

public static double getDouble() { double x = 0.0; while (true) {

String str = readRealString(); if (str.equals("")) {

errorMessage("Illegal floating point input",

"Real number in the range " + Double.MIN_VALUE + " to " + Double.MAX_VALUE);

else {

Double f = null;

try { f = Double.valueOf(str); } catch (NumberFormatException e) {

errorMessage("Illegal floating point input", "Real number in the range " + Double.min_value + " to " + Double.max_value);

continue;

}

if (f.islnfinite()) {

errorMessage("Floating point input outside of legal range.", "Real number in the range " + Double.min_value + " to " + Double.max_value);

continue;

}

x = f.doubleValue(); break;

}

}

return x;

}

public static String getWord() { char ch = lookChar(); while (ch == ‘ ‘ || ch == ‘\n’) { readChar(); if (ch == ‘\n’)

dumpString("? ", 0) ; ch = lookChar();

}

StringBuffer str = new StringBuffer(50); while (ch !=”&& ch != ‘\n’) { str.append(readChar()); ch = lookChar();

}

return str.toString();

public static boolean getBoolean() { boolean ans = false; while (true) {

String s = getWordO;

if (s.equalsIgnoreCase("true") || s.equalsIgnoreCase("t") II

s.equalsIgnoreCase("yes") || s.equalsIgnoreCase("у") II s.equals("1")) { ans = t rue^- break;

}

else if (s.equalsIgnoreCase("false") || s.equalsIgnoreCase("f") II s.equalsIgnoreCase("no") || s.equalsIgnoreCase("n") || s.equals("0")) { ans = falser- break;

}

else

errorMessage("Illegal boolean input value.",

"one of: true, false, t, f, yes, no, y, n, 0, or 1");

}

return ans;

}

II ***************** далее следуют значения private ***********

II ************* вспомогательные процедуры для ввода и вывода ********

private static InputStream in = System.in;

/ / новое имя для потока ввода private static PrintStream out = System.out;

// новое имя для потока вывода private static String buffer = null; // чтение строки из потока ввода private static int pos = 0;

// положение следующего необработанного // символа в строке ввода private static String readRealString()

{ // чтение символа в соответствии с синтаксисом представления

// чисел с плавающей точкой

StringBuffer s=new StringBuffer(50);

char ch=lookChar() ;

while (ch == ‘ ‘ || ch == ‘\n’) { readChar() ; if (ch == ‘\n’)

dumpString("? ", 0) ; ch = lookChar();

}

if (ch ==     || ch == ‘+’) {

s.append(readChar()) ; ch = lookChar(); while (ch == ‘ ‘) { readChar(); ch = lookChar();

}

}

while (ch >= ‘0’ && ch <= ‘9’) { s.append(readChar ()); ch = lookChar();

}

if (ch == ‘.’) {

s.append(readChar ()); ch = lookChar();

while (ch >= ‘0’ && ch <= ‘9’) { s.append(readChar()); ch = lookChar();

}

}

if (ch == ‘E’ || ch == ‘e’) { s.append(readChar()); ch = lookChar(); if (ch ==   || ch == ‘+’) {

s.append(readChar()); ch = lookChar();

}

while (ch >= ‘0’ && ch <= ‘9’) { s.append(readChar()) ; ch = lookChar();

}

}

return s.toString();

}

private static long readlnteger(long min, long max) { // чтение длинного целого в заданных пределах long х=0; while (true) {

StringBuffer s=new StringBuffer(34); char ch=lookChar(); while (ch == ‘ ‘ || ch == ‘\n’) { readChar(); if (ch == ‘\n’);

dumpString("? ", 0) ; ch = lookChar();

}

if (ch ==            || ch == ‘+’) {

s.append(readChar() ) ; ch = lookChar(); while (ch == ‘ ‘) { readChar(); ch = lookChar();

}

}

while (ch >= ‘0’ && ch <= ‘9’) { s.append(readChar()); ch = lookChar();

}

if (s.equals ("")){

errorMessage("Illegal integer input.",

"Integer in the range " + min + " to " + max);

}

else {

String str = s.toString(); try {

x = Long.parseLong(str) ;

}

catch (NumberFormatException e) {

errorMessage("Illegal integer input.",

"Integer in the range " + min + " to " + max) ;

continue;

}

if (x < min || x > max) {

errorMessage("Integer input outside of legal range.",

"Integer in the range " + min + " to " + max);

continue;

}

break;

}

}

return x;

}

private static String realToString(double x) {

// Получение представления числа с плавающей точкой длиной // в 10 или 11 (для отрицательного значения) символов, if (Double.isNaN(х))

return "undefined"; if (Double.islnfinite(x)) if (x < 0)

return "-INF"; else

return "INF";

if (Math.abs(x) <= 5000000000.0 && Math.rint(x) == x)

return String.valueOf((long)x); String s = String.valueOf(x); if (s.length () <= 10)

return s; boolean neg = false; if (x < 0) { neg = true; x = -x;

s = String.valueOf(x) ;

}

if (x >= 0.00005 && x <= 50000000 && (s.indexOf(‘E’) == -1 && s.indexOf(‘e’) == -1))

{ // оставляем максимальное число символов, равное 10 s = round(s,10); s = trimZeros (s);

}

else if (x > 1) { // строим экспоненциальное представление с положительным // показателем

long power = (long)Math.floor(Math.log(x)/Math.log(10)); String exp = "E" + power; int numlength = 10 — exp.length(); x = x / Math.pow(10,power); s = String.vaiueOf(x); s = round(s,numlength); s = trimZeros(s) ; s += exp;

}

else {

long power = (long)Math.ceil(-Math.log(x)/Math.log(10)); String exp = "E-" + power; int numlength = 10 — exp.length(); x = x * Math.pow(10,power); s = String.vaiueOf(x); s = round(s,numlength); s = trimZeros(s); s += exp;

}

if (neg)

return "-" + s; else

return s;

}

private static String trimZeros(String num) { // используется в методе realToString

if (num.indexOf(‘.’) >= 0 && num.charAt(num.length() — 1) == ‘0’) { int i = num.length() — 1; while (num.charAt(i) == ‘0’) i—;

if (num.charAt(i) == ‘.’)

num = num.substring(0,i); else

num = num.substring(0,i+1);

}

return num;

}

private static String round(String num, int length) { // используется в методе realToString if (num.indexOf(‘ . ‘) < 0)

return num; if (num.length() <= length) return num;

if (num.charAt(length) >= ‘5’ && num.charAt(length) != ‘.’) { char[] temp = new char[length+1]; int ct = length; boolean rounding = true; for (int i = length-1; i >= 0; i—) { temp[ct] = num.charAt(i); if (rounding && temp[ct] !=’.’) { if (temp[ct] < ‘9’) { temp[ct]++; rounding = false;

}

else

temp[ct] = ‘0’;

}

ct—;

}

if (rounding) { temp[ct] = ‘ ‘; ct—;

}

// ct равно -1 или 0

return new String(temp,ct+1,length-ct);

else

return num.substring(0,length);

}

private static void dumpString(String str, int w) { // вывод строки на консоль

for (int i=str.length(); i<w; i++) out.print(‘ ‘);

for (int i=0; i<str.length(); i++)

if ((int)str.charAt(i) >= 0x20 && (int)str.charAt(i) != 0x7F) // нет символов, подлежащих удалению out.print(str.charAt(i)); else if (str.charAt(i) == ‘\n’ || str.charAt(i) == ‘\r’) newLine();

}

private static void errorMessage(String message, String expecting) { // Сообщение пользователю об ошибке и предложение повторить ввод. newLine();

dumpString(" *** Error in input: " + message + "\n", 0) ; dumpString(" *** Expecting: " + expecting + "\n", 0); dumpString(" *** Discarding Input: ", 0); if (lookChar() == ‘\n’)

dumpString("(end-of-line)\n\n",0); else {

while (lookChar() != ‘\n’)

out.print(readChar()) ; dumpString("\n\n",0);

}

dumpString("Please re-enter: ", 0); readChar(); // игнорирует символы в конце

}

private static char lookChar() { // возвращает следующий введенный символ return next character from input

if (buffer == null || pos > buffer.length())

fillBuffer(); if (pos == buffer.length())

return ‘\n'; return buffer.charAt(pos);

private static char readChar()

{ // возвращает следующий символ в потоке ввода и игнорирует его char ch = lookChar(); pos++; return ch;

}

private static void newLine()

{ // выводит на консоль символ CR out.println(); out.flush();

}

private static boolean possibleLinefeedPending = falser- private static void fillBuffer ()

{ // Ожидает пользовательский ввод, // помещает ввод в буфер. StringBuffer b = new StringBuffer(); out.flush(); try {

int ch = in.read();

if (ch == ‘\n’ && possibleLinefeedPending)

ch = in.read(); possibleLinefeedPending = falser- while (ch != -1 && ch != ‘\n1 && ch != ‘\r’) { b.append((char)ch) ; ch = in.read();

}

possibleLinefeedPending = (ch == ‘\r’) ; if (ch == -1) {

System.out.printIn("\n* * * Found an end-of-file while trying

to read from standard input!"); System.out.printIn("* * * Maybe your Java system doesn’t

implement standard input?"); System.out.printIn("* * * Program will be terminated.\n"); throw new RuntimeException("End-of-file on standard input.");

}

}

catch (IOException e) {

System.out.println("Unexpected system error on input.");

System.out.println("Terminating program."); System.exit(1);

}

buffer = b.toStringO ; pos = 0;

}

private static void emptyBuffer()

{ // игнорирует оставшуюся часть строки ввода buffer = null;

}

}

Источник: Будилов В. А. Интернет-программирование на Java. — СПб.: БХВ-Петербург, 2003. — 704 е.: ил.

По теме:

  • Комментарии