Расширение функциональности элементов пользовательского интерфейса в java


Содержание

27. Java – Интерфейсы

Интерфейс — это ссылочный тип в Java. Он схож с классом. Это совокупность абстрактных методов. Класс реализует интерфейс, таким образом наследуя абстрактные методы интерфейса.

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

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

Содержание

Написание интерфейса схоже с написанием класса. Но класс описывает атрибуты и поведения объекта. И интерфейс содержит поведения, которые класс реализует.

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

Чем похожи класс и интерфейс?

Интерфейс схож с классом следующим образом:

  • Интерфейс может содержать любое количество методов.
  • Интерфейс записан в файле с расширением .java, и имя интерфейса совпадает с именем файла.
  • Байт-код интерфейса находится в .class файле.
  • Интерфейсы появляются в пакетах, и их соответствующий файл байт-кода должен быть в структуре каталогов, которая совпадает с именем пакета.

Чем отличается класс от интерфейса?

Однако, интерфейс всё же отличается от класса. Отличие интерфейса от класса в Java:

  • Вы не можете создать экземпляр интерфейса.
  • В интерфейсе не содержатся конструкторы.
  • Все методы в интерфейсе абстрактные.
  • Интерфейс не может содержать поля экземпляров. Поля, которые могут появиться в интерфейсе, обязаны быть объявлены и статическими, и final.
  • Интерфейс не расширяется классом, он реализуется классом.
  • Интерфейс может расширить множество интерфейсов.

Объявление интерфейсов

Ключевое слово interface используется для объявления интерфейса. Вот пример того, как можно создать интерфейс:

Пример 1

Интерфейсы имеют следующие свойства:

  • Интерфейс абстрактный косвенно. Вам не нужно использовать ключевое слово abstract во время объявления интерфейса.
  • Каждый метод в интерфейсе косвенно абстрактным, поэтому ключевое слово abstract не нужно.
  • Методы в интерфейсе косвенно публичны.

Пример 2

Реализация интерфейса

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

Класс использует ключевое слово implements для реализации интерфейса. Ключевое слово implements появляется при объявлении класса в его расширенной части.

Пример

При переопределении методов в интерфейсе, нужно следовать некоторым правилам:

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

При реализации интерфейсов есть некоторые правила:

  • Класс может реализовать более одного интерфейса за раз.
  • Класс может расширить только один класс, но реализовать множество интерфейсов.
  • Интерфейс может расширить другой интерфейс таким же образом, как класс расширяет другой класс.

Расширение интерфейсов

Интерфейс может расширять другой интерфейс так же, как класс другой класс. Ключевое слово extends используется для расширения интерфейса, и дочерний интерфейс наследует методы родительского интерфейса.

Приведённый интерфейс Sports расширен интерфейсами Hockey и Football.

Пример

Интерфейс Hockey имеет четыре метода, но он наследует два из Sports; таким образом, класс, который реализует Hockey, должен реализовать все шесть методов. Подобно этому, класс, который реализует Football, должен определить три метода из Football и два метода из Sports.

Расширение множества интерфейсов

Класс в Java может расширить только один родительский класс. Множественное наследование невозможно. Однако интерфейсы не классы, и интерфейс может расширить более чем один родительский интерфейс.

Ключевое слово extends используется лишь раз, а родительские интерфейсы объявляются через запятую.


Например, если интерфейс Hockey расширил и Sports, и Event, то объявление выглядело бы так:

Интерфейсы тегов

Самое распространённое использование расширения интерфейсов происходит тогда, когда родительский интерфейс не содержит каких-либо методов. Например, интерфейс MouseListener в пакете java.awt.event расширил java.util.EventListener, который определяется так:

Интерфейс без методов в нём называется интерфейсом тегов. Есть две простые дизайнерские цели для интерфейсов тегов:

Создаёт общего родителя – как в случае с интерфейсом EventListener, который расширяется множеством других в Java API, вы можете использовать интерфейс тегов, чтобы создать общего родителя среди группы интерфейсов. Например, когда интерфейс расширяет EventListener, то JVM знает, что этот конкретный интерфейс будет использоваться в сценарии делегирования событий.

Добавляет тип данных в класс – эта ситуация является источником термина «тегирование». Класс, который реализует интерфейс тегов, не должен определять какие-либо методы (т.к. интерфейс не имеет таковых), но класс становится типом интерфейса через полиморфизм.

Графический интерфейс на Java Swing — GUI Tutorial

В Java есть 2 основных пакета для создания графических интерфейсов (Graphics User Interface). Это Abstract Windows Toolkit (AWT) и Swing. AWT использует виджеты операционной системы, поэтому эта библиотека немного быстрее. Но на мой взгляд, Swing более хорошо спроектирован.

В данном туториале мы рассмотрим основные элементы библиотеки Swing и создадим простой интерфейс (GUI) в качестве примера.

Для группировки компонент интерфейса используются контейнеры (Container). Для создания основного контейнера для приложения чаще всего используется контейнер JFrame (есть еще JWindows и JApplet). Проще всего унаследоваться от JFrame тем самым получить доступ ко множеству методов, например:

setBounds(x, y, w, h) — указывает координаты верхней левой вершины окна, а также его ширину и высоту.

setResizable(bool) — указывает, можно ли изменять размер окна.

setTitle(str) — устанавливает название окна.

setVisible(bool) — собственно отображает окно.

setDefaultCloseOperation(operation) — указывает операцию, которая будет произведена при закрытии окна.

Основные элементы управления:

  • JLabel — элемент для отображения фиксированного текста;
  • JTextField — простой edit-box;
  • JButton — обычная кнопка (button);
  • JCheckBox — элемент выбора (аналог checkbox);
  • JRadioButton — радио кнопка

Как видите, все довольно просто и логично.

При отображении элементов управления используются специальные менеджеры — LayoutManager. У всех LayoutManager’ов есть методы для добавления у удаления элементов.

FlowLayout — используется для последовательного отображения элементов. Если элемент не помещается в конкретную строку, он отображается в следующей.

GridLayout — отображения элементов в виде таблицы с одинаковыми размерами ячеек.

BorderLayout — используется при отображении не более 5 элементов. Эти элементы располагаются по краям фрейма и в ценрте: North, South, East, West, Center.

BoxLayout — отображает элементы в виде рядка или колонки.

GridBagLayout — позволяет назначать месторасположение и размер каждого виджета. Это самый сложный, но и самый эффективный вид отображения.

Стоит еще обратить внимание на обработку событий. Для этого используются так называемые Event Listeners.

Ну все, довольно теории, перейдем к примеру GUI:

getContentPane возвращает контейнер верхнего уровня. ButtonGroup служит для создания группы взаимосвязанных радио-кнопок.

Внутренний класс ButtonActionListener реализует интерфейс ActionListener. Для этого необходимо предоставить имплементацию метода actionPerformed.

JOptionPane служит для отображения диалоговых окон.

Жду ваших вопросов и комментариев. Если вы хотите больше узнать о Swing, скажите об этом, и в скором времени я напишу еще одну статью с более сложными приемами и компонентами.

Функциональный интерфейс

1. Что такое функциональный интерфейс

Чтобы иметь возможность использовать лямбда выражения, необходим интерфейс:

Лямбда выражения не содержат информацию о том, какой функциональный интерфейс они реализуют.

Тип выражения выводится из контекста, в котором используется лямбда выражение. Этот тип называется целевой тип (target type).

Если лямбда выражение присваивается какому-то интерфейсу, лямбда выражение должно соответствовать синтаксису метода интерфейса.

Одно и то же лямбда выражение может использоваться с разными интерфейсами, если они имеют абстрактные методы, которые совместимы. Например:

Функциональный интерфейс (functional interface) – это интерфейс у которого только один абстрактный метод. Функциональный интерфейс может содержать любое количество методов по умолчанию (default) или статических методов. Например:


Еще один пример функционального интерфейса:

Функциональный интерфейс может содержать методы класса Object :

В Java 8 была введена аннотация @FunctionalInterface , которая генерирует ошибку компиляции, если интерфейс не является функциональным:

Примеры функциональных интерфейсов: java.lang.Runnable , java.util.Comparator.

2. Лямбда vs анонимные классы

Лямбда выражения являются альтернативой анонимным классам. Но они не одинаковы.

  1. Локальные переменные могут быть использованы только если они final или effective final .
  2. Разрешается доступ к переменным класса и статическим переменным класса.
  3. Они не должны выбрасывать больше исключений чем определено в throws метода функционального интерфейса.
  1. Для анонимных классов ключевое слово this ссылается на сам класс. Для лямбда выражений на внешний класс.
  2. Анонимные классы компилируются во внутренние классы. Но лямбда выражения преобразуются в статические private методы класса, в котором они используют invokedynamic инструкцию. Лямбда более эффективны, так как не надо загружать еще один класс.

3. Встроенные функциональные интерфейсы

В Java 8 добавлены встроенные функциональные интерфейсы в пакет java.util.function :

4. Бинарные специализации функциональных интерфейсов

Существуют бинарные специализации (binary specializations) интерфейсов Predicate , Consumer , Function и UnaryOperator , которые принимают на вход два элемента.

Функциональный дескриптор BiConsumer
BiFunction
BiPredicate
BinaryOperator

5. Примитивные специализации функциональных интерфейсов

5.1. Predicate

Описание
IntPredicate
LongPredicate
DoublePredicate

5.2. Consumer

Принимает на вход значение типа int и ничего не возвращает .

Описание
IntConsumer
LongConsumer

Принимает на вход значение типа long и ничего не возвращает .

DoubleConsumer

5.3. Function

Принимающие примитивные специализации

Принимает на вход значение типа int и возвращает значение типа R .

Описание
IntFunction
LongFunction
DoubleFunction

Производящие примитивные специализации

Принимает на вход значение типа T и возвращает значение типа int .

Описание
ToIntFunction
ToDoubleFunction

Принимает на вход значение типа T и возвращает значение типа double .


ToLongFunction

Принимает на вход значение типа T и возвращает значение типа long .

ez code

Просто о сложном.

Интерфейсы в Java

В некоторых ситуациях, в процессе разработки программного обеспечения, возникает необходимость, когда разным группам программистов надо «договориться» о том, как их программы будут взаимодействовать. Каждая группа должна иметь возможность писать свой код не зависимо от того, как пишет его другая группа. Интерфейсы и есть этот «договор». Мы уже пользовались интерфейсами в уроке аннотации в Java.
В этом уроке мы изучим их подробнее: для чего они нужны, как их объявлять и т.д.

Представьте себе будущее, где автомобилями управляют компьютеры без участия человека. Производители автомобилей пишут программное обеспечение (на Java, конечно �� ), которое управляет машиной — остановиться, поехать, повернуть и т.д. Другие разработчики делают системы, которые принимают данные GPS (Global Positioning System) и используют эти данные для управления автомобилем. Производители автомобилей публикуют интерфейс-стандарт, который описывает методы для управления машиной. Таким образом сторонние разработчики могут знать какие методы вызывать, чтобы заставить автомобиль двигаться, а производители автомобилей могут изменять внутреннюю реализацию своего продукта в любое время. Ни одна из групп разработчиков не знает как написаны их программы.

Интерфейсы Java

Интерфейсы в Java во многом напоминают классы, но могут содержать только константы, сигнатуры методов и вложенные типы. В интерфейсах нет описания методов. Нельзя создать объект типа интерфейса (но можно использовать в качестве типа — интерфейсные ссылки, об этом позже) — интерфейсы могут только реализовываться некоторым классом или наследоваться другим интерфейсом. Объявление интерфейса очень похоже на объявление класса:

Сигнатуры методов объявляются без скобок и заканчиваются точкой с запятой. Для использования интерфейса вы должны написать класс, который будет реализовывать ваш интерфейс. Класс который реализует интерфейс, должен описывать все методы, объявленные в интерфейсе. Например:

В примере выше — производители автомобилей пишут программное обеспечение каждый по-своему, но с одинаковым интерфейсом. Сторонние разработчики — клиенты интерфейса, могут писать собственно ПО с использованием методов, объявленных в интерфейсе.

Интерфейсы в качестве API

Пример с автомобилями показывает как интерфейсы могут использоваться в качестве API (Application Programming Interface) или интерфейса программирования приложений. Использование API — обычная практика при разработке коммерческого ПО. Обычно компании-разработчики продают программное обеспечение, содержащее набор методов, которые другие компании хотят использовать в своих продуктах.

Интерфейсы и множественное наследование

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

Объявление интерфейса

Объявление интерфейса содержит ключевое слово interface , имя интерфейса, список родительских интерфейсов через запятую (если есть) и тело интерфейса. Например:

Модификатор доступа public означает что интерфейс может быть использован любым классом в любом пакете. Если не определить интерфейс как публичный, он будет доступен только в рамках своего пакета. Интерфейс может наследовать другие интерфейсы, как классы могут наследовать другой класс. В отличие от классов, интерфейсы могут наследовать любое количество других интерфейсов.

Реализация интерфейса

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

Пример простого интерфейса

Рассмотрим интерфейс, который определяет метод для сравнения объектов.

Чтобы иметь возможность сравнивать объекты мы должны реализовать интерфейс Relatable . Любой класс может реализовать интерфейс Relatable , если есть способ сравнить объекты. Для строк сравнивать можно количество символов, для книг — количество страниц, для студентов — вес и т.д. Для плоских геометрических фигур отличной характеристикой будет площадь, для трехмерных — объем. Все эти классы могут реализовать метод isLargerThan() . Если вы знаете, что класс реализует интерфейс Relatable , то вы смело можете сравнивать объекты этого класса.

Реализация интерфейса Relatable

Напишем класс Rectangle , реализующий интерфейс Relatable .

Так как класс RectanglePlus реализует Relatable , размеры любых двух объектов типа RectanglePlus можно сравнивать.

Метод isLargerThan в качестве аргумента принимает объекты типа Relatable . При реализации метода в примере выше мы используем приведение типов, потому что компилятор не поймет что, other — объект типа RectanglePlus и вызов метода other.getArea() без приведения типов приведет к ошибке.

Использование интерфейса в качестве типа

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

Рассмотрим пример — метод, который ищет больший объект из двух любых объектов, класс которых реализует интерфейс Relatable :

Приведением object1 к типу Relatable , мы делаем возможным вызов метода isLargerThan .

Так же для любого класса, реализующего интерфес Relatable, можно реализвать методы:

Переопределение интерфейсов

Допустим, вы написали интерфейс DoIt :

Предположим, позже, вы захотели добавить в него третий метод:

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

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

Теперь пользователи вашего интерфейса смогут перейти к использованию нового интерфейса или остаться со старым без боли.

Интерфейсы в Java и немного о полиморфизме


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

Новички часто спрашивают, чем интерфейс отличается от абстрактного класса. Интерфейсы в Java компенсируют отсутствие множественного наследования классов. У класса-потомка может быть только один абстрактный класс-родитель, а вот интерфейсов класс может применять (имплементировать) сколько угодно.

Интерфейс на Java объявляют примерно так же, как и класс:

В имплементирующем интерфейс классе должны быть реализованы все предусмотренные интерфейсом методы, за исключением методов по умолчанию.

Методы по умолчанию впервые появились в Java 8. Их обозначают модификатором default. В нашем примере это метод say_goodbye, реализация которого прописана прямо в интерфейсе. Дефолтные методы изначально готовы к использованию, но при необходимости их можно переопределять в применяющих интерфейс классах.

Функциональный интерфейс Java

Если у интерфейса только один абстрактный метод, перед нами функциональный интерфейс. Его принято помечать аннотацией @FunctionalInterface, которая указывает компилятору, что при обнаружении второго абстрактного метода в этом интерфейсе нужно сообщить об ошибке. Стандартных (default) методов у интерфейса может быть множество – в том числе принадлежащих классу java.lang.Object.

Как выглядит функциональный интерфейс на Java:

Функциональные интерфейсы появились в Java 8. Они обеспечили поддержку лямбда-выражений, использование которых делает код лаконичным и понятным:

В той же версии появились пакеты встроенных интерфейсов: java.util.function и java.util.stream.

Реализация интерфейсов классами Java

Допустим, есть интерфейс Edible, которым пользуются классы Fruit, Vegetable, Fish. Экземпляры этих классов можно создавать так:

Хорошим тоном считается давать интерфейсам названия с окончанием -able/-ible — это показывает, что с объектами, имплементирующими интерфейс, можно что-то делать: Edible (можно есть), Moveable (можно двигать), Clickable (реагирует на клик) и т.д.

Обратите внимание на разницу в конструкторах: для фруктов задаём название и сорт, для рыбы – название, район вылова и вес порции в граммах. Но ссылки на оба объекта храним в переменных одного типа – «Съестное».

Интерфейсы и полиморфизм

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

В Java полиморфизм можно реализовать через:

  • наследование — с переопределением параметров и методов базового класса;
  • абстрактные классы — шаблоны для раздельной реализации в разных классах;
  • интерфейсы — для имплементации классами.

Интерфейс выручает в ситуации, когда при создании переменной мы не знаем, объект какого класса ей будет присвоен.

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

Новички часто спрашивают, чем интерфейс отличается от абстрактного класса. Интерфейсы в Java компенсируют отсутствие множественного наследования классов. У класса-потомка может быть только один абстрактный класс-родитель, а вот интерфейсов класс может применять (имплементировать) сколько угодно.

Интерфейс на Java объявляют примерно так же, как и класс:

В имплементирующем интерфейс классе должны быть реализованы все предусмотренные интерфейсом методы, за исключением методов по умолчанию.

Методы по умолчанию впервые появились в Java 8. Их обозначают модификатором default. В нашем примере это метод say_goodbye, реализация которого прописана прямо в интерфейсе. Дефолтные методы изначально готовы к использованию, но при необходимости их можно переопределять в применяющих интерфейс классах.

Функциональный интерфейс Java

Если у интерфейса только один абстрактный метод, перед нами функциональный интерфейс. Его принято помечать аннотацией @FunctionalInterface, которая указывает компилятору, что при обнаружении второго абстрактного метода в этом интерфейсе нужно сообщить об ошибке. Стандартных (default) методов у интерфейса может быть множество – в том числе принадлежащих классу java.lang.Object.

Как выглядит функциональный интерфейс на Java:

Функциональные интерфейсы появились в Java 8. Они обеспечили поддержку лямбда-выражений, использование которых делает код лаконичным и понятным:

В той же версии появились пакеты встроенных интерфейсов: java.util.function и java.util.stream.

Реализация интерфейсов классами Java

Допустим, есть интерфейс Edible, которым пользуются классы Fruit, Vegetable, Fish. Экземпляры этих классов можно создавать так:

Хорошим тоном считается давать интерфейсам названия с окончанием -able/-ible — это показывает, что с объектами, имплементирующими интерфейс, можно что-то делать: Edible (можно есть), Moveable (можно двигать), Clickable (реагирует на клик) и т.д.

Обратите внимание на разницу в конструкторах: для фруктов задаём название и сорт, для рыбы – название, район вылова и вес порции в граммах. Но ссылки на оба объекта храним в переменных одного типа – «Съестное».

Интерфейсы и полиморфизм

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

В Java полиморфизм можно реализовать через:

  • наследование — с переопределением параметров и методов базового класса;
  • абстрактные классы — шаблоны для раздельной реализации в разных классах;
  • интерфейсы — для имплементации классами.

Интерфейс выручает в ситуации, когда при создании переменной мы не знаем, объект какого класса ей будет присвоен.


Java 8 интерфейсы

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

Интерфейсы в Java являются ссылочными типами, как классы, но они могут содержать в себе только константы, сигнатуры методов, default методы (методы по умолчанию), static методы (статические методы) и вложенные типы. Тела методов могут быть только у статических методов и методов по умолчанию.

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

Пример интерфейса, описывающий общие методы для всех монстров:

Интерфейсы в Java. Полное руководство

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

Например, нам нужно создать рисунок, который состоит из нескольких фигур. Для этого мы можем создать интерфейс Shape и определить методы для работы с объектами Shape. Для простоты, давайте определим только два метода — draw() — чтобы нарисовать фигуру и метод getArea() , который будет возвращать площадь фигуры.

Пример Java интерфейса

На основании вышеуказанных требований, наш интерфейс Shape будет выглядеть следующим образом:

Основная информация об интерфейсах в Java

  • interface — ключевое слово для создания интерфейса в Java.
  • Создать экземпляр интерфейса в Java нельзя.
  • Интерфейс обеспечивает абсолютную абстракцию. В прошлых постах мы узнали об абстрактных классах в Java, которые также обеспечивают абстракцию, но абстрактные классы могут иметь реализаций метода, а интерфейс не может.
  • Интерфейсы не могут иметь конструкторов, потому что мы не можем создать экземпляр интерфейса. Также интерфейсы не могут иметь методы с реализацией.
  • По умолчанию любой атрибут интерфейса является public, static и final, так что нам не нужно определять модификаторы доступа к атрибутам. Если же вы попробуете это сделать, то компилятор жаловаться не будет.
  • По умолчанию методы интерфейса неявно abstract и public. Это очень умное решение, потому что в интерфейсе метод не имеет реализации — этим занимаются подклассы, реализующие этот интерфейс.
  • Интерфейс в Java не может быть подклассом у другого класса, но он может реализовать другой интерфейс. public interface Shape extends Cloneable<> — пример интерфейса, который наследует другой интерфейс. На самом деле Java обеспечивает множественное наследование интерфейсов — это означает, что интерфейс может наследовать несколько интерфейсов.
  • Ключевое слово implements используется классами для реализации интерфейса.
  • Класс, реализующий интерфейс, должен обеспечить реализацию всех его метода, если только это не абстрактный класс. Например, мы можем реализовать наш интерфейс в абстрактном классе. Вот пример:
  • Программисты должны писать программы в терминах интерфейсов, а не реализаций, потому что в будущем переписать реализацию интерфейса можно будет и в новом классе.

Пример реализации интерфейса на Java

Теперь давайте посмотрим на реализацию интерфейса Shape:

Обратите внимание, что класс Circle реализует все методы, определенные в интерфейсе, а также собственный метод getRadius() . Реализация интерфейса может иметь несколько типов конструкторов. Давайте посмотрим другую реализацию интерфейса Shape.

А теперь напишем программу для тестирования реализаций нашего интерфейса.

Результат работы программы будет такой:

Преимущества интерфейсов в Java

  • Интерфейс обеспечивает так называемый контракт для всех классов, которые реализуют интерфейс.
  • Интерфейсы хороши для создания начальной точки и создания иерархии в проекте.

Недостатки интерфейсов в Java

Хотя интерфейсы дают программисту множество преимуществ, они также имеют и недостатки.

Введение в разработку графического интерфейса

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

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


Более детальное руководство по функциям разработки конструктора графического интерфейса пользователя, включая видеодемонстрации различных функций разработки см. в разделе Разработка графического пользовательского интерфейса Swing в IDE NetBeans.

Предполагаемая продолжительность: 20 минут

Содержание

Для работы с этим учебным курсом требуются программное обеспечение и ресурсы, перечисленные ниже.

Программное обеспечение или материал Требуемая версия
IDE NetBeans с Java SE версия 6.9 или более поздняя
Комплект для разработчика на языке Java (JDK) версия 6, 7 или 8

Упражнение 1: Создание проекта

Первым действием является создание проекта среды IDE для разрабатываемого приложения. Дадим проекту имя NumberAddition.

  1. Выберите "Файл" >"Создать проект". Также можно щелкнуть значок «New Project» на панели инструментов среды IDE.
  2. В области «Categories» выберите узел «Java». В области «Projects» выберите «Java Application». Нажмите кнопку «Далее».
  3. Введите NumberAddition в поле Project Name («Имя проекта») и укажите путь, например, в вашем основном каталоге, как местоположение проекта.
  4. Установите флажок «Использовать отдельную папку для хранения библиотек» и укажите местоположение папки библиотек (необязательно). Дополнительная информация приведена в статье Предоставление доступа к библиотеке другим пользователям в документе Разработка приложений с помощью NetBeans IDE.
  5. Удалите флажок «Create Main Class», если он установлен.
  6. Нажмите кнопку ‘Готово’.

Упражнение 2: Создание внешнего интерфейса

Для продолжения процесса создания интерфейса необходимо создать контейнер Java, в который будут помещены другие требуемые элементы графического интерфейса. В этом действии контейнер будет создан с помощью элемента JFrame . Контейнер будет помещен в новый пакет, который будет отображаться в узле «Source Packages».

Создание контейнера JFrame

  1. В окне ‘Проекты’ щелкните правой кнопкой мыши узел NumberAddition и выберите Создать >Другие.
  2. В диалоговом окне создания файла выберите категорию Swing GUI Forms и тип файла JFrame Form. Нажмите кнопку «Далее».
  3. Введите NumberAdditionUI в качестве имени класса.
  4. Выберите пакет my.numberaddition .
  5. Нажмите кнопку ‘Готово’.

Среда IDE создает форму NumberAdditionUI и класс NumberAdditionUI в приложении NumberAddition и открывает форму NumberAdditionUI в GUI Builder. Пакет my.NumberAddition заменяет собой пакет по умолчанию.

Добавление элементов: создание внешнего интерфейса

Далее с помощью окна «Palette» внешний интерфейс приложения заполняется панелью JPanel. После этого добавляются три элемента JLabel (текстовые подписи), три элемента JTextField (текстовые поля) и три элемента JButton (кнопки). Если до этого работа с конструктором графического интерфейса пользователя не выполнялась сведения о размещения компонентов см. в разделе Разработка графического пользовательского интерфейса Swing в IDE NetBeans.

После перетаскивания и размещения указанных выше элементов элемент JFrame должен выглядеть так, как показано на рисунке ниже.

Если в правом верхнем углу среды IDE отсутствует окно Palette («Палитра»), выберите Window («Окно») > Palette («Палитра»).

  1. Для начала выберите панель из категории Swing Containers («Контейнеры Swing») в палитре и перетащите ее на JFrame.
  2. Панель JPanel будет выделена. Перейдите к окну «Properties» и нажмите кнопку с многоточием (. ) рядом с полем «Border» для выбора стиля границы.
  3. В диалоговом окне «Border» выберите «TitledBorder» из списка и введите Number Addition в поле «Title». Для сохранения изменений и закрытия диалогового окна нажмите кнопку «OK».
  4. Теперь на экране должен отображаться пустой элемент «JFrame» с заголовком «Number Addition», как показано на рисунке. Согласно рисунку добавьте к нему три метки JLabel, три текстовых поля JTextField и три кнопки JButton.

Переименование элементов

На этом этапе будет выполнено переименование элементов, которые были добавлены к элементу JFrame.

  1. Дважды щелкните jLabel1 и измените ntrcn (свойство «text») на First Number .
  2. Дважды щелкните jLabel2 и измените текст на Second Number .
  3. Дважды щелкните jLabel3 и измените текст на Result .
  4. Удалите стандартный текст из jTextField1 . Отображаемый текст можно преобразовать в редактируемый. Для этого щелкните правой кнопкой мыши текстовое поле и выберите ‘Редактировать текст’ во всплывающем меню. При этом может потребоваться восстановить первоначальный размер поля jTextField1 . Повторите это действие для полей jTextField2 и jTextField3 .
  5. Измените отображаемый текст jButton1 на Clear . (Для изменения текста кнопки щелкните кнопку правой кнопкой мыши и выберите «Edit Text». В качестве альтернативы можно щелкнуть кнопку, выдержать паузу и щелкнуть еще раз.)
  6. Измените отображаемый текст jButton2 на Add .
  7. Измените отображаемый текст jButton3 на Exit .

Теперь готовый графический интерфейс должен выглядеть так, как показано на рисунке ниже:

Упражнение 3: Добавление функциональности

В этом упражнении будет добавлена необходимая функциональность к кнопкам «Add», «Clear» и «Exit». Поля jTextField1 и jTextField2 будут использоваться для ввода значений пользователем, а jTextField3 – для вывода результата работы программы. Создаваемая программа представляет собой простейший калькулятор. Итак, приступим!

Добавление функциональности к кнопке «Exit»

Для того чтобы кнопки стали функциональными, каждой из них необходимо присвоить обработчик событий, который будет отвечать за реагирование на события. В нашем случае требуется идентифицировать событие нажатия кнопки – путем щелчка мышью или с помощью клавиатуры. Поэтому будет использоваться интерфейс «ActionListener», предназначенный для обработки событий «ActionEvent».

  1. Щелкните правой кнопкой мыши кнопку «Exit». Во всплывающем меню выберите Events («События») > Action («Действие») > actionPerformed. Учтите, что меню содержит множество других событий, на которые может реагировать программа! При выборе события actionPerformed среда IDE автоматически добавит прослушиватель ActionListener к кнопке Exit («Выход») и создаст метод обработчика для обработки метода прослушивателя actionPerformed.
  2. В среде IDE автоматически открывается окно «Source Code», где отображается место вставки действия, которое должно выполняться кнопкой при ее нажатии (с помощью мыши или клавиатуры). Окно «Source Code» должно содержать следующие строки:
  3. Теперь добавим код действия, которое должна выполнять кнопка «Exit». Замените строку TODO на System.exit(0); . Готовый код кнопки «Exit» должен выглядеть следующим образом:

Добавление функциональности к кнопке «Clear»


  1. Щелкните вкладку «Design» в верхней части рабочей области для возврата к экрану «Form Design».
  2. Щелкните правой кнопкой мыши кнопку «Clear» ( jButton1 ). В появившемся меню выберите «Events > Action > actionPerformed».
  3. Нажатие кнопки «Clear» должно приводить к удалению всего текста из всех текстовых полей «jTextField». Для этого следует добавить код, аналогичный приведенному выше. Готовый исходный код должен выглядеть следующим образом:

Этот код удаляет текст из всех трех полей JTextField, оставляя их пустыми.

Добавление функциональности к кнопке «Add»

Кнопка «Add» должна выполнять три действия.

  1. Сначала она принимает данные, введенные пользователем в полях jTextField1 и jTextField2 , и преобразовывает их из типа «String» в тип «Float».
  2. Затем она выполнит сложение двух чисел.
  3. И, наконец, она преобразует сумму в тип String и поместит ее в jTextField3 .

Начнем!

  1. Щелкните вкладку «Design» в верхней части рабочей области для возврата к экрану «Form Design».
  2. Щелкните правой кнопкой мыши кнопку «Add» ( jButton2 ). Во всплывающем меню выберите Events («События») > Action («Действие») > actionPerformed.
  3. Добавьте код действий, которые должна выполнять кнопка «Add». Готовый исходный код должен выглядеть следующим образом:

Теперь программа полностью готова, и можно приступить к ее сборке и выполнению.

Упражнение 4: Выполнение программы

Для выполнения программы в среде IDE выполните следующие действия:

    Выберите Run («Запуск») > Run Main Project («Запуск главного проекта») (как вариант, нажмите F6).

Примечание. При открытии окна с указанием того, что для Project NumberAddition не задан основной класс, следует выбрать my.NumberAddition.NumberAdditionUI в качестве основного класса в том же окне и нажать кнопку ОК.

Для запуска программы вне среды IDE выполните следующие действия:

  1. Для сборки архива JAR приложения выберите «Run > Clean and Build Main Project» (Shift-F11).
  2. При помощи проводника по файловой системе или диспетчера файлов перейдите в каталог NumberAddition/dist .

Примечание. Местоположение каталога проекта NumberAddition зависит от пути, указанного при создании проекта в шаге 3 в разделе Упражнение 1. Создание проекта.

  • Дважды щелкните файл NumberAddition.jar .
  • Через несколько секунд приложение запустится.

    Примечание. Если при двойном щелчке файла JAR не выполняется запуск приложения, дополнительные сведения о настройке связей файлов JAR в используемой операционной системе см эту статью.

    Можно также запустить приложение из командной строки.

    Для запуска приложения из командной строки выполните следующие действия:

    1. Вызовите командную строку или окно терминала.
    2. В командной строке измените текущий каталог на каталог NumberAddition/dist .
    3. В командной строке введите следующий оператор:

    Примечание. Убедитесь, что my.NumberAddition.NumberAdditionUI задан как основной класс до запуска приложения. Для провери этого, щелкните правой кнопкой узел мыши узел проекта NumberAddition на панели ‘Проекты’, выберите ‘Свойства’ во всплывающем меню и выберите категорию ‘Выполнить’ в диалоговом окне ‘Свойства проекта’. В поле ‘Основной класс’ должно отображаться my.numberaddition.NumberAdditionUI.

    Механизм обработки событий

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

    1. Вернитесь к файлу NumberAdditionUI.java в редакторе. Щелкните вкладку «Design» для просмотра структуры графического интерфейса в GUI Builder.
    2. Щелкните правой кнопкой мыши любой элемент графического интерфейса и выберите «Events» в появившемся меню. Теперь можно просто изучить содержимое меню, не выбирая каких-либо пунктов.
    3. В качестве альтернативы можно выбрать «Properties» в меню «Window». В окне «Properties» щелкните вкладку «Events». Вкладка «Events» позволяет просмотреть и изменить обработчики событий, связанные с текущим активным элементом графического интерфейса.
    4. Приложение также может реагировать на нажатие клавиш, одинарный, двойной или тройной щелчок мышью, перемещение указателя мыши, изменение размера окна и перемещение фокуса ввода. Меню «Events» позволяет автоматически создать обработчики событий для всех этих событий. Наиболее распространенным из них является событие «Action». (Для получения дополнительных сведений см. практические рекомендации по обработке событий в руководстве Sun Java Events Tutorial.)

    Как выполняется обработка событий? При каждом выборе события из меню событий среда IDE автоматически создает так называемый прослушиватель событий и связывает его с компонентом разработчика. Для более подробного ознакомления с процессом обработки событий выполните следующие действия.

    1. Вернитесь к файлу NumberAdditionUI.java в редакторе. Щелкните вкладку «Source» для просмотра исходного кода графического интерфейса.
    2. Выполните прокрутку вниз и просмотрите реализованные методы jButton1ActionPerformed() , jButton2ActionPerformed() и jButton3ActionPerformed() . Эти методы называются обработчиками событий.
    3. Теперь перейдите к методу initComponents() . Если этот метод отсутствует, найдите строку Generated Code и щелкните знак + рядом с этой строкой для отображения скрытого метода initComponents() .
    4. Обратите внимание на синий блок, окружающий метод initComponents() . Этот код был автоматически создан средой IDE и не может быть изменен пользователем.
    5. Теперь посмотрите на сам метод initComponents() . Помимо прочего, он содержит код, инициализирующий элементы графического интерфейса и помещающий их в форму. Этот код создается и обновляется автоматически при размещении и изменении элементов в режиме проектирования.
    6. В методе initComponents() найдите следующий фрагмент:

    В этом месте к элементу графического интерфейса, в данном случае к jButton3 , добавляется объект прослушивания событий «ActionListener». Интерфейс «ActionListener» имеет метод «actionPerformed» объекта «ActionEvent», который реализуется путем простого вызова обработчика событий jButton3ActionPerformed . Теперь эта кнопка реагирует на события действий. Каждый раз при нажатии кнопки создается событие «ActionEvent», которое передается в метод «actionPerformed» интерфейса прослушивания событий, исполняющий код, предусмотренный разработчиком для этого события в обработчике событий.

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

    Занятие 4

    Интерфейсы

    Абстрактные классы

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


    Например, классы Point (точка), Circle (круг) и Rectangle (прямоугольник) унаследованы от класса Figure (фигура). В классе Figure есть метод paint() , общий для всех подклассов — он нужен, чтобы нарисовать фигуру. Но между рисованием круга, точки и прямоугольника нет ничего общего, поэтому бессмысленно программировать этот метод в классе Figure .

    В таких случаях после заголовка метода и списка параметров вместо фигурных скобок ставится точка с запятой, а перед объявлением метода указывается ключевое слово abstract . Такой метод называется абстрактным, т.е. лишенным реализации.

    Класс, в котором есть хотя бы один абстрактный метод, называется абстрактным классом и перед словом class должно также стоять слово abstract .

    Создать объект абстрактного класса нельзя. Можно только унаследовать от этого класса другие классы, переопределить в них абстрактные методы (наполнив их конкретным содержимым) и создавать объекты уже этих классов. *

    Множественное наследование

    Множественным наследованием называется ситуация, когда класс наследует от двух или более классов.

    Пусть, например, уже разработаны классы Clock (часы) и Phone (телефон) и возникает необходимость написать новый класс Cellurar (сотовый телефон), который совмещает в себе структуру и поведение обоих этих классов (его можно использовать как телефон, но он обладает также всей функциональностью часов). Очень удобно просто унаследовать класс Cellular от классов Clock и Phone . Во-первых, программисту не приходится заново переписывать многочисленные методы. Во-вторых, сохраняются все преимущества полиморфизма: объект класса Cellular можно использовать в программе и в качестве часов (как объект класса Clock ) и в качестве телефона (как объект класса Phone ).

    Однако множественное наследование потенциально способно породить трудноразрешимые проблемы. Они начинаются, когда у классов-предков есть методы с одинаковыми сигнатурами (т.е. именем и числом параметров).

    Например, в классе Clock есть метод ring() , который вызывается, когда срабатывает таймер будильника. Но в классе Phone тоже есть метод ring() , который вызывается, когда кто-то звонит по телефону и надо оповестить об этом владельца. Когда класс Cellular наследует от классов Clock и Phone , он получает метод ring() . Но какой из его вариантов? *

    У этой ситуации нет безупречного решения. Поэтому многие языки программирования запрещают множественное наследование.

    Java множественное наследование не поддерживает.

    Заметим, однако, что если метод ring() хотя бы в одном из классов Clock и Phone является абстрактным, то конфликта возникнуть не может. Абстрактный метод не имеет реализации, а следовательно «побеждает» тот метод, который абстрактным не является. Если же метод является абстрактным в обоих классах, он останется таким же и в их потомке.

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

    Понятие интерфейса в Java. Описание интерфейса

    представляет собой класс, в котором все поля — константы (т.е. статические — static и неизменяемые — final ), а все методы абстрактные.

    При описании интерфейса вместо ключевого слова class используется ключевое слово interface , после которого указывается имя интерфейса, а затем, в фигурных скобках список полей-констант и методов. Никаких модификаторов перед объявлением полей и методов ставить не надо: все поля автоматически становятся public static final , а методы — public abstract . Методы не могут иметь реализации, т.е. после закрывающей круглой скобки сразу ставится точка с запятой.

    Опишем, например, интерфейс для объекта, который «умеет» сообщать информацию о себе в формате прайс-листа (т.е. сообщать свое название, цену, и краткое описание).

    Для разнообразия метод getPrice() в этом примере требует один целочисленный параметр (количество единиц товара).

    Такой интерфейс полезен для программы типа Интернет-магазин, которая должна по запросу пользователя формировать прайс — перечень товаров с указанием их цены и описания.

    Реализация интерфейса

    Класс может реализовывать интерфейс, т.е. перенимать его поведение. Эта процедура аналогична наследованию, только вместо ключевого слова extends используется ключевое слово implements . Но если после extends может быть указан только один класс, то после implements можно перечислить через запятую произвольное количество интерфейсов. Класс может одновременно наследовать от другого класса и реализовывать интерфейсы.

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

    Класс Dog2 «умеет» то же самое, что и старый класс Dog , но помимо этого его можно использовать в программе Интернет-магазина для формирования прайса. Обратите внимание, класс Dog ничего не знал о цене, поэтому понадобилось добавить метод setPrice() и поле price , чтобы эту цену можно было бы изменять. А изменять описание собаки не понадобится, поэтому метод getDescription() просто выводит одну и ту же сроку.

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

    Переменные интерфейсного типа

    Переменные интерфейсного типа могут ссылаться на объект любого класса, реализующего данный интерфейс.

    PriceItem pi; // переменная интерфейсного типа Dog2 dog = new Dog2(); // создается объект класса Dog2, на него ссылается переменная dog dog.voice(); // можно вызвать метод лая System.out.println(dog.getTitle()); // можно вывести название товара Dog oldDog = dog; // переменная oldDog ссылается на тот же самый объект oldDog.voice(); // можно работать с объектом нового класса по-старому pi = dog; // переменная pi рассматривает тот же самый объект как товар для прайса pi.voice(); // НЕ ПОЛУЧИТСЯ. Этого метода нет в интерфейсе PriceItem *

    Мы можем поместить собак, велосипеды и компьютеры в один массив goods (товары) и в цикле сформировать прайс:

    PriceItem[] goods; . // создание и заполнение массива элементами, // поддерживающими интерфейс PriceItem for ( int i = 0; i System.out.println( «Название: » + goods[i].getTitle() + «, цена за единицу товара: » + goods[i].getPrice(1) + «, описание: » + goods[i].getDescription() + «.» ); >

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

    Приемы программирования: пример применения интерфейсов

    Предположим, в нашей программе есть объект, который следит за текущим временем и каждую минуту (когда время меняется) «сообщает» об этом другим объектам. Это очень логичный и удобный способ организации программы, в которой объекты должны что-то делать при наступлении определенного времени (или события). Гораздо лучше, чем учить каждый объект следить за временем.

    Один объект может «сообщить» что-то другому объекту, вызвав его метод. Пусть информацию о времени обрабатывает метод sayTime(int hours, int minutes) . Для того, чтобы вызвать этот метод у какого-то объекта, надо быть уверенным, что такой метод описан в классе этого объекта. Можно определить интерфейс, скажем TimeListener , и реализовать его во всех классах, которым нужно следить за временем, не вмешиваясь в основную иерархию этих классов. И тогда у нас может быть разновидность умной собаки, которая лает ровно в полночь и разновидность кнопки, которая может автоматически срабатывать через заданный промежуток времени.

    Класс, следящий за временем будет иметь внутренний список объектов типа TimeListener , методы для добавления и удаления объектов в этот список (те объекты, которые «захотят» следить за временем, вызовут этот метод) и каждую минуту объект этого класса (достаточно одного такого объекта на всю программу) будет вызывать метод sayTime(int hours, int minutes) для каждого из объектов в этом списке.

    Пакеты и области видимости

    Пакеты

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

    Каждый пакет имеет имя. Имя представляет собой обычный идентификатор Java. Особенность заключается в том, что это имя одновременно является названием папки, в которой хранятся файлы классов, входящие в пакет. А точка в имени преобразуется в разделитель имен файловой системы. То есть пакет с именем java.util будет представлен папкой util , находящейся внутри папки java .

    В папке хранятся файлы с расширением .java , содержащие описания классов, входящих в пакет. В начале такого файла должен стоять оператор package , после которого записывается имя пакета.


    Импортирование пакетов

    Полное имя класса состоит из идентификатора, указанного после ключевого слова class и предшествующего ему имени пакета, в котором этот класс находится. Классы ClassA и ClassB , описанные в пакете package1 , имеют полные имена package1.ClassA и package1.ClassB .

    Классы, находящиеся внутри одного пакета могут пользоваться сокращенными именами друг друга (что мы до сих пор всегда и делали). В одном из методов класса ClassA можно определить переменную класса ClassB , создать объект класса ClassB и вызвать его метод (например, f() ) командами:

    >new ClassB(); varb.f();

    package1. >new package1.ClassB(); varb.f();

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

    Это ограничение можно обойти, если импортировать нужный класс из другого пакета.

    Для импортирования класса используется ключевое слово import , после которого указывается его полное имя. Например, можно импортировать класс Vector из пакета java.util :

    Теперь можно пользоваться именем Vector вместо java.util.Vector .

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

    импортирует все файлы из пакета java.util . Но таким способом пользоваться не рекомендуется, так как при этом из разных пакетов могут импортироваться файлы с одинаковыми именами. *

    Eclipse позволяет облегчить жизнь разработчику. Если в программе используется класс с неизвестным именем, на полях редактора кода появляется значок предупреждения об ошибке. Щелчок по этому значку выводит варианты решения проблемы. Например, создать новый класс. Или импортировать существующий (при этом выводится список всех доступных пакетов, содержащих класс с таким именем). Если выбрать вариант «Import» соответствующая директива import будет автоматически добавлена в начало пакета.

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

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

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

    Рекомендуется для названия пакета использовать адрес сайта фирмы-разработчика. Адреса сайтов есть практически у всех серьезных разработчиков программ (и, что самое главное, адреса сайтов не могут совпадать). Адрес сайта рекомендуется записывать наоборот. То есть, если адрес — sun.com, то имя пакета должно начинаться с com.sun. Кстати, таких пакетов довольно много в вашей системе, их поставляет фирма Sun Microsystems, разработчик языка Java.

    Файловая структура Java-проекта

    Итак, Java-проект может состоять из нескольких пакетов. Каждому пакету в файловой структуре операционной системы соответствует одна папка.

    В пакете могут содержаться классы и интерфейсы. Они хранятся в файлах с расширением .java.

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

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

    Eclipse создает новый файл с расширением .java автоматически, если выполнить команду New Class или New Interface .

    Файл с расширением .java — это обычный текстовый файл. Его можно открывать и редактировать как с помощью Eclipse, так и в любом другом текстовом редакторе (даже в Блокноте).

    Для каждого класса (открытого или закрытого) Java создает файл с расширением .class . Это двоичный файл, в котором хранятся команды на внутреннем языке Java. Эти файлы недоступны для редактирования в Eclipse (если попытаться их открыть, Eclipse на самом деле откроет соответствующий .java -файл). Чтобы они не мешали, их можно скрыть с помощью фильтра. Для этого в представлении Navigator нажмите маленькую треугольную кнопку справа ( menu ) и выберите команду Filters. В открывшемся окне поставьте галочку напротив расширения .class , чтобы скрыть из панели Navigator соответствующие файлы.

    Области видимости классов

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

    Объект, созданный в области видимости своего класса, может продолжать свое существование и за ее пределами. Но переменные типа «невидимого» класса объявить нельзя, поэтому обращаться к такому объекту можно только с помощью переменных типов «видимых» классов-предков. Следовательно, и вызывать можно лишь те методы объекта, которые его класс унаследовал от соответствующего предка.

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

    Вложенные классы, объявленные без модификатора public , видны только в методах содержащего их класса. Классы, описанные в методах, видны только в пределах этих методов.

    Анонимные классы видны лишь в пределах команды, которой они создаются.

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

    Члены класса (методы и атрибуты), объявленные как public , видны везде, где виден сам класс.

    Члены класса, объявленные как protected видны в самом классе и его потомках.

    Члены класса, объявленные как private , видны только в пределах класса.

    Если к члену класса не применяется ни один из модификаторов public , private , protected , он виден в пределах текущего пакета.

    «Видимость» поля означает, что его можно использовать в выражениях, передавать в качестве аргумента в методы, изменять его значение с помощью присваивания.

    «Видимость» метода означает возможность его вызова.

    Для обращения к полям и методам класса используется полное имя, состоящее из имени объекта соответствующего класса и собственно имени атрибута или метода. В теле метода того же класса имя объекта можно опускать (если подразумевается this — объект, для которого вызван данный метод).

    Области видимости переменных

    Переменные, объявленные в теле метода, видны от места объявления до конца блока, в котором это объявление находится. Границы блока задаются фигурными скобками <> . Поэтому в следующем примере:

    используются две разные переменные x (первая переменная, равная 0, перестает существовать за границами своего блока).

    Переменные, являющимися параметрами метода, видны во всем теле метода.

    Перечисленные переменные называются локальными переменными. Двух локальных переменных с одинаковыми именами и перекрывающимися областями видимости быть не должно. Нельзя, например, объявить две переменных следующим образом:

    Нельзя, в частности, объявлять в теле метода переменную, совпадающую (по имени) с одним из параметров метода.

    Конфликты имен

    Конфликт имен возникает, если в одной области видимости оказываются два объекта с одинаковыми именами, причем такая ситуация является в языке разрешенной (в противном случае это не конфликт имен, а ошибка в программе).

    Конфликт имен возникает, когда импортируются два пакета, содержащие классы с одинаковыми именами.

    В этом случае Java отдает предпочтение классу, который был импортирован первым. Для обращения ко остальным классам следует использовать их полные имена.

    Java «просматривает» имена классов в следующем порядке. Сначала — классы, импортированные поодиночке. Потом — классы, определенные в данном пакете. В последнюю очередь классы из пакетов, импортируемых полностью в порядке следования команд import .

    Конфликт имен возникает так же, когда имя одного из параметров метода совпадает с именем одного из атрибутов этого же класса. Такая ситуация возникает довольно часто, поскольку для метода, изменяющего значение этого атрибута, такое называние параметра довольно наглядно. Например:

    Такой заголовок метода setAge(int age) лучше, чем использовавшийся нами на прошлом занятии setAge(int a) , поскольку сразу позволяет судить о назначении параметра. Однако возникает вопрос: к чему будет относиться имя age в теле этого метода — к атрибуту или к параметру.

    Ответ: к параметру. Имя параметра «перекрывает» имя атрибута.

    Для того, чтобы обратиться к атрибуту, следует использовать полное имя (т.е. указатель на объект this ).

    Реализация метода должна выглядеть следующим образом:

    Дополнительная литература

    1. Вязовик Н.А. Программирование на Java. (глава 8)

    2. Хабибуллин И.Ш. Самоучитель Java 2. (глава 3)

    java — Расширение функциональности простого графического интерфейса пользователя

    Я пытаюсь научить себя, как сделать графический интерфейс с использованием Java swing и Window Builder Pro, после просмотра нескольких видеороликов YouTube и чтения некоторых руководств, а также задав предыдущий вопрос, который я нашел здесь, я выполнил следующее.

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

    У меня есть несколько функций, которые я хотел бы реализовать, но я не уверен, как двигаться вперед.

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

    Другой вариант, который я хотел бы прояснить, — это редактирование содержимого выпадающего списка после построения. В идеале я хотел бы иметь возможность добавлять и удалять записи из поля с помощью нажатия кнопок. Я не могу найти метод, который позволяет мне установить содержимое поля, и, как представляется, единственный способ добиться этого — создать новый combobox каждый раз при внесении изменений. Есть ли более эффективный способ сделать это?

    Илон Маск рекомендует:  Модель визуального форматирования
    Понравилась статья? Поделиться с друзьями:
    Кодинг, CSS и SQL