В объектно-ориентированном программировании (ООП) внутренний класс или вложенный класс — это класс, объявленный полностью внутри тела другого класса или интерфейса. Он отличается от подкласса .
Экземпляр обычного или верхнего уровня класса может существовать сам по себе. Напротив, экземпляр внутреннего класса не может быть создан без привязки к верхнему уровню класса.
Давайте возьмем абстрактное понятие a Car
с четырьмя Wheel
s. Наши Wheel
s имеют определенную особенность, которая основана на том, что они являются частью нашего Car
. Это понятие не представляет Wheel
s как Wheel
s в более общей форме, которая могла бы быть частью любого транспортного средства. Вместо этого оно представляет их как специфичные для a Car
. Мы можем смоделировать это понятие с помощью внутренних классов следующим образом:
У нас есть класс верхнего уровня Car
. Экземпляры класса Car
состоят из четырех экземпляров класса Wheel
. Эта конкретная реализация Wheel
специфична для автомобиля, поэтому код не моделирует общее понятие колеса, которое было бы лучше представить как класс верхнего уровня. Поэтому он семантически связан с классом Car
, а код Wheel
некоторым образом связан с его внешним классом, являясь единицей композиции автомобиля. Колесо для конкретного автомобиля уникально для этого автомобиля, но для обобщения колесо является единицей агрегации для автомобиля.
Внутренние классы предоставляют механизм для точного моделирования этой связи. Мы можем ссылаться на наш Wheel
класс как на Car.Wheel
, Car
будучи классом верхнего уровня и Wheel
будучи внутренним классом.
Таким образом, внутренние классы обеспечивают объектную ориентацию определенных частей программы, которые в противном случае не были бы инкапсулированы в класс.
Более крупные сегменты кода внутри класса могут быть лучше смоделированы или рефакторированы как отдельный класс верхнего уровня, а не как внутренний класс. Это сделало бы код более общим в своем применении и, следовательно, более пригодным для повторного использования, но потенциально может быть преждевременным обобщением. Это может оказаться более эффективным, если код имеет много внутренних классов с общей функциональностью.
В Java существует четыре типа вложенных классов:
static
. Как и другие вещи в статической области действия (т. е. статические методы ), они не имеют охватывающего экземпляра и не могут получить доступ к переменным экземпляра и методам охватывающего класса. Они почти идентичны невложенным классам, за исключением деталей области действия (они могут ссылаться на статические переменные и методы охватывающего класса без указания имени; другие классы, которые не являются одним из его охватывающих классов, должны указывать свое имя именем своего охватывающего класса). Вложенные интерфейсы неявно являются статическими.Внутренний класс – Следующие категории называются внутренними классами . Каждый экземпляр этих классов имеет ссылку на включающий экземпляр (т. е. экземпляр включающего класса), за исключением локальных и анонимных классов, объявленных в статическом контексте. Следовательно, они могут неявно ссылаться на переменные экземпляра и методы включающего класса. Ссылку на включающий экземпляр можно получить явно через EnclosingClassName.this
. Внутренние классы не могут иметь статических переменных или методов, за исключением постоянных переменных времени компиляции. Когда они создаются, они должны иметь ссылку на экземпляр включающего класса; это означает, что они должны быть либо созданы внутри метода экземпляра или конструктора включающего класса, либо (для классов-членов и анонимных классов) созданы с использованием синтаксиса enclosingInstance.new InnerClass()
. [1]
Локальные внутренние классы часто используются в Java для определения обратных вызовов для кода GUI. Затем компоненты могут совместно использовать объект, реализующий интерфейс обработки событий или расширяющий абстрактный класс адаптера, содержащий код, который должен быть выполнен при возникновении данного события.
Анонимные внутренние классы также используются в тех случаях, когда код обработки событий используется только одним компонентом и, следовательно, не нуждается в именованной ссылке.
Это позволяет избежать большого монолитного actionPerformed(ActionEvent)
метода с несколькими ветвями if-else для определения источника события. Этот тип кода часто считается беспорядочным [ требуется цитата ] и внутренние вариации класса считаются лучшими во всех отношениях. [ требуется цитата ]