Многие люди могут быть не знакомы с внутренними классами Java. Фактически, аналогичная концепция существует в C++, то есть вложенных классах. Различия и связи между ними будут сравниваться ниже. На первый взгляд внутренний класс — это просто еще один класс, определенный внутри класса (как вы увидите ниже, внутренние классы могут быть определены во многих местах), но на самом деле все не так просто. На первый взгляд внутренние классы кажутся немного странными. Польза может быть не так очевидна для новичков, но при более глубоком ее понимании вы обнаружите, что разработчики Java действительно имеют благие намерения в отношении внутренних классов. Обучение использованию внутренних классов является частью освоения продвинутого программирования на Java, которое позволяет вам более элегантно проектировать структуру программы. Давайте представим его со следующих сторон:
первая встреча
Скопируйте код кода следующим образом:
Публичный интерфейс Содержание {
целое значение();
}
Публичный интерфейс Назначение {
Строка readLabel();
}
Товары общественного класса {
частный класс Content реализует Contents {
частный интервал я = 11;
публичное значение int() {
вернуть я;
}
}
защищенный класс GDestination реализует Destination {
частная строковая метка;
частный GDestination (StringwhereTo) {
метка = куда;
}
публичная строка readLabel() {
возвратная этикетка;
}
}
общедоступное место назначения (String s) {
вернуть новые GDestination(s);
}
публичное содержимое cont() {
вернуть новый контент();
}
}
класс TestGoods {
public static void main(String[] args) {
Товары p = новые товары();
Содержание c = p.cont();
Пункт назначения d = p.dest("Пекин");
}
}
В этом примере классы Content и GDestination определены внутри класса Goods и имеют модификаторы protected и Private соответственно для управления уровнями доступа. Content представляет содержимое Товаров, а GDestination представляет пункт назначения Товаров. Они реализуют два интерфейса Content и Destination соответственно. В следующем основном методе вы напрямую используете Contents c и Destination d. Вы даже не видите имена этих двух внутренних классов! Таким образом, первое преимущество внутренних классов — это скрытие операций, о которых вы не хотите, чтобы другие знали, то есть инкапсуляция.
В то же время мы также обнаружили первый способ вывести объект внутреннего класса за пределы области действия внешнего класса, а именно создать и вернуть его с помощью методов его внешнего класса. Это делают методы cont() и dest() в приведенном выше примере. Так есть ли другой способ?
Конечно, есть,
формат синтаксиса следующий:
externalObject = новый внешний класс (параметры конструктора);
externalClass.innerClass внутреннийОбъект=outerObject.new InnerClass(Параметры конструктора);
Обратите внимание: при создании нестатического объекта внутреннего класса необходимо сначала создать соответствующий объект внешнего класса. Что касается причины, это приводит к нашей следующей теме. Нестатические объекты внутреннего класса имеют ссылки на объекты внешнего класса.
Немного измените предыдущий пример:
Скопируйте код кода следующим образом:
Товары общественного класса {
частный int valueRate = 2;
частный класс Content реализует Contents {
частный int я = 11 * valueRate;
публичное значение int() {
вернуть я;
}
}
защищенный класс GDestination реализует Destination {
частная строковая метка;
частный GDestination (StringwhereTo) {
метка = куда;
}
публичная строка readLabel() {
возвратная этикетка;
}
}
общедоступное место назначения (String s) {
вернуть новые GDestination(s);
}
публичное содержимое cont() {
вернуть новый контент();
}
}
Здесь мы добавляем в класс Goods частную переменную-член valueRate, что означает коэффициент стоимости товара. Он умножается на него, когда метод value() внутреннего класса Content вычисляет значение. Мы обнаружили, что value() может получить доступ к valueRate, что является вторым преимуществом внутренних классов. Объект внутреннего класса может получить доступ к содержимому объекта внешнего класса, который его создал, даже к частным переменным! Это очень полезная функция, которая дает нам больше идей и ярлыков при проектировании. Для достижения этой функции объект внутреннего класса должен иметь ссылку на объект внешнего класса. Когда компилятор Java создает объект внутреннего класса, он неявно передает ссылку на объект внешнего класса и сохраняет ее. Это позволяет объекту внутреннего класса всегда иметь доступ к своему объекту внешнего класса, и именно поэтому, чтобы создать объект внутреннего класса вне области действия внешнего класса, вы должны сначала создать его объект внешнего класса.
Некоторые люди могут спросить, что делать, если переменная-член внутреннего класса имеет то же имя, что и переменная-член внешнего класса, то есть переменная-член внешнего класса с тем же именем заблокирована? Это нормально. Java использует следующий формат для выражения ссылок на внешние классы:
внешнийкласс.это
Благодаря этому мы не боимся этой защитной ситуации.
статический внутренний класс
Как и обычные классы, внутренние классы также могут быть статическими. Однако по сравнению с нестатическими внутренними классами разница состоит в том, что статические внутренние классы не имеют внешних ссылок. На самом деле это очень похоже на вложенные классы в C++. Самая большая разница между внутренними классами Java и вложенными классами C++ заключается в том, есть ли ссылки на внешний мир. Конечно, с точки зрения дизайна и некоторых его деталей, разница есть.
Кроме того, в любом нестатическом внутреннем классе не может быть статических данных, статических методов или другого статического внутреннего класса (внутренние классы могут быть вложены более чем на один уровень). Но все это можно разместить в статических внутренних классах. Это можно рассматривать как второе различие между ними.
локальный внутренний класс
Да, внутренние классы Java также могут быть локальными, они могут быть определены внутри метода или даже блока кода.
Скопируйте код кода следующим образом:
Товары общественного класса1 {
общедоступное место назначения (String s) {
класс GDestination реализует Destination {
частная строковая метка;
частный GDestination (StringwhereTo) {
метка = куда;
}
публичная строка readLabel() {
возвратная этикетка;
}
}
вернуть новые GDestination(s);
}
public static void main(String[] args) {
Товар1 g = новый Товар1();
Пункт назначения d = g.dest("Пекин");
}
}
Вышеуказанное является одним из таких примеров. В методе dest мы определяем внутренний класс, и, наконец, этот метод возвращает объект этого внутреннего класса. Если нам нужно только создать объект внутреннего класса и создать его снаружи, мы можем это сделать. Конечно, внутренние классы, определенные в методах, могут разнообразить дизайн, и их использование этим не ограничивается.
Вот еще более странный пример:
Скопируйте код кода следующим образом:
Товары общественного класса2 {
Private void InternalTracking (логическое значение b) {
если (б) {
класс TrackingSlip {
частный строковый идентификатор;
TrackingSlip(String s) {
идентификатор = с;
}
Строка getSlip() {
вернуть идентификатор;
}
}
TrackingSlip ts = новый TrackingSlip("промах");
Строка s = ts.getSlip();
}
}
публичный недействительный трек() {
InternalTracking (истина);
}
public static void main(String[] args) {
Товар2 g = новый Товар2();
г.трек();
}
}
Вы не можете создать объект этого внутреннего класса вне if, потому что он выходит за рамки его области действия. Однако во время компиляции внутренний класс TrackingSlip компилируется одновременно с другими классами, за исключением того, что он имеет собственную область действия и недействителен за пределами этой области. В остальном он ничем не отличается от других внутренних классов.
анонимный внутренний класс
Правила синтаксиса анонимных внутренних классов Java могут показаться немного странными, но, как и в случае с анонимными массивами, когда вам нужно только создать объект класса и не нужно его имя, использование внутренних классов может сделать код кратким и понятным. Его синтаксические правила следующие:
новое имя интерфейса(){......} или новое имя суперкласса(){......};
Продолжим пример ниже:
Скопируйте код кода следующим образом:
Товары общественного класса3 {
публичное содержимое cont() {
вернуть новое содержимое() {
частный интервал я = 11;
публичное значение int() {
вернуть я;
}
};
}
}
Здесь метод cont() использует анонимный внутренний класс для прямого возврата объекта класса, реализующего интерфейс Contents, который действительно выглядит очень просто.
В анонимных адаптерах для обработки событий Java широко используются анонимные внутренние классы. Например, если вы хотите закрыть окно, добавьте этот код:
Скопируйте код кода следующим образом:
Frame.addWindowListener(новый WindowAdapter(){
public void windowClosing(WindowEvent e){
Система.выход(0);
}
});
Следует отметить, что, поскольку анонимный внутренний класс не имеет имени, у него нет и конструктора (но если анонимный внутренний класс наследует родительский класс, который содержит только параметризованный конструктор, он должен передать эти параметры при его создании и использовать супер ключевое слово для вызова соответствующего контента в процессе реализации). Если вы хотите инициализировать его переменные-члены, есть несколько методов:
Если он находится в анонимном внутреннем классе метода, вы можете использовать этот метод для передачи нужных параметров, но помните, что эти параметры должны быть объявлены как окончательные.
Преобразуйте анонимный внутренний класс в именованный локальный внутренний класс, чтобы у него был конструктор.
Используйте блок инициализации в этом анонимном внутреннем классе.
Зачем вам нужны внутренние классы?
Каковы преимущества внутренних классов Java? Зачем вам нужны внутренние классы?
Для начала разберем простой пример. Если вы хотите реализовать интерфейс, но метод в этом интерфейсе имеет то же имя и параметры, что и метод в задуманном вами классе, что делать? На данный момент вы можете создать внутренний класс для реализации этого интерфейса. Поскольку внутренний класс доступен для всего, что есть во внешнем классе, это позволит реализовать всю функциональность, которая была бы у вас, если бы вы реализовали интерфейс напрямую.
Но у вас может возникнуть вопрос: не достаточно ли просто изменить метод?
Действительно, использовать это как причину для проектирования внутренних классов действительно неубедительно.
Настоящая причина заключается в следующем. Вместе внутренние классы и интерфейсы Java могут решить проблему, на которую часто жалуются программисты C++ в Java без множественного наследования. На самом деле множественное наследование в C++ очень сложно спроектировать, а в Java можно очень хорошо добиться эффекта множественного наследования с помощью внутренних классов и интерфейсов.