Внутренние классы Java (анонимные или нет): хорошо ли их использовать? - PullRequest
20 голосов
/ 18 февраля 2010

В некоторых моих проектах и ​​в некоторых книгах было сказано, что не используйте внутренний класс (анонимный или нет, статический или нет) - за исключением некоторых ограниченных условий, таких как EventListener s или Runnable с - это лучшая практика. Они даже были «запрещены» в моем первом промышленном проекте.

Это действительно лучшая практика? Почему?

(Я должен сказать, что я часто их использую ...)

- РЕДАКТИРОВАТЬ ---
Я не могу выбрать правильный ответ во всех этих ответах: в большинстве из них есть доля правильности: я все еще буду использовать внутренние классы, но я постараюсь использовать их реже!

Ответы [ 15 ]

1 голос
/ 18 февраля 2010

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

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

1 голос
/ 18 февраля 2010

Анонимные внутренние классы часто используются, когда нам нужно реализовать интерфейс с одним методом, таким как Runnable, ActionListener и некоторыми другими.

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

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

Java также имеет вложенные (или внутренние статические) классы. Их можно использовать, если вы хотите предоставить какой-то особый доступ, а стандартных общедоступных или стандартных уровней доступа недостаточно.

1 голос
/ 18 февраля 2010

Внутренние классы подходят при попытке эмулировать множественное наследование.Это похоже на то, что происходит под капотом в C ++: когда у вас есть множественное наследование в C ++, расположение объектов в памяти фактически является объединением нескольких экземпляров объекта;Затем компилятор выясняет, как указатель this должен быть настроен при вызове метода.В Java нет множественного наследования, но внутренний класс можно использовать для предоставления «представления» данного экземпляра под другим типом.

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

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

(Небольшой недостаток внутренних классов заключается в том, что они добавляют один дополнительный уровеньОтступы в исходном коде. Иногда это немного утомительно, когда хочется сохранить код в 79 столбцах.)

0 голосов
/ 16 февраля 2019

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

Типичный класс с отложенной загрузкой создается с идентификатором объекта, а затем по запросу может лениво загружать дополнительную информацию об объекте. Обычно для ленивой загрузки дополнительной информации нам потребуются зависимости. Но зависимости + состояние == анти шаблон!

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

/*
 * Stateless outer class holding dependencies
 */
public class DataAssembler {
  private final LoadingService loadingService;

  @Inject
  DataAssembler(LoadingService loadingService) {
    this.loadingService = loadingService;
  }

  public LazyData assemble(long id) {
    return new LazyData(id);
  }

  /*
   * Stateful non-static inner class that has access to the outer
   * class' dependencies in order to lazily load data.
   */
  public class LazyData {
    private final long id;

    private LazyData(long id) {
      this.id = id;
    }

    public long id() {
      return id;
    }

    public String expensiveData() {
      return loadingService.buildExpensiveDate(id);
    }
  }
}

Стоит отметить, что помимо вышеприведенного примера есть много других шаблонов, в которых полезны внутренние классы; внутренние классы похожи на любую другую функцию Java - есть подходящее время, когда их можно использовать, и неподходящее время!

0 голосов
/ 18 февраля 2010

да, это полезно, когда вы пытаетесь сохранить связность классов, и никогда не следует создавать экземпляры классов вне контекста внешнего класса, делайте конструкторы частными, и у вас будет действительно хорошая связная инкапсуляция. Тот, кто говорит, что вы должны НИКОГДА использовать их, не знает, о чем они говорят. Для обработчиков событий и других вещей, в которых превосходят анонимные внутренние классы, они намного лучше, чем альтернатива засорения пространства имен вашего пакета множеством обработчиков событий, которые применяются только к определенному классу.

...