Подтвердить что ты не робот

Java (анонимные или нет) внутренние классы: полезно ли их использовать?

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

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

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

- ИЗМЕНИТЬ ---
Я не могу выбрать правильный ответ во всех этих ответах: есть часть правильности в основном для всех из них: я по-прежнему буду использовать внутренние классы, но я постараюсь использовать их реже!

4b9b3361

Ответ 1

На мой взгляд, 90% внутренних классов в Java-коде являются либо сущностями, которые связаны с одним классом, и, таким образом, "заперты" в качестве внутренних классов или анонимными внутренними классами, которые существуют, потому что Java не поддерживает Lambdas.

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

Это оставляет меня с необходимыми внутренними классами, такими как прослушиватели действий, фальшивое "функциональное" программирование и т.д. Они часто анонимны, и хотя я не поклонник (во многих случаях я бы предпочел Лямбду), я живу с но им не нравятся.

Я не делал никаких С# в течение многих лет, но мне интересно, не уменьшается ли распространенность внутренних классов или что-то вроде эквивалента С# при введении Lambdas.

Ответ 2

Чистота. Легче понять код, если он разбит на логические фрагменты, а не все в одном файле.

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

Ответ 3

Анонимные классы полезны при использовании программирования на основе событий, особенно в качелях.

Ответ 4

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

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

Ответ 5

Анонимные внутренние классы имеют преимущества в том, что они могут видеть поля и переменные вокруг "нового" оператора. Это может сделать для очень чистого дизайна и довольно приятный (но немногословный) подход к "как мы можем сделать простую версию лямбда-операторов".

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

Ответ 6

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

public void doGet(HttpServletRequest request, final HttpServletResponse response){
  createSubscription(..., new SubscriptionListener(){
    public void subscriptionCreated(final CallController controller) {
      response.setStatus(200);
      ...
      controller.resume();
    }

    public void subscriptionFailed(){
       ...
     }

    public void subscriptionTimeout(){
      ...
  }});
}

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

Используйте их, но будьте осторожны!

Martin

Ответ 7

Определенные структуры, такие как Wicket, действительно требуют анонимных внутренних классов.

Говорить никогда не бывает глупо. Никогда не говори никогда! Примером хорошего использования может быть ситуация, когда у вас есть какой-то унаследованный код, написанный кем-то, где многие классы действуют непосредственно в поле "Коллекция", и по какой-либо причине вы не можете изменить эти другие классы, но вам необходимо условно зеркально отразить операции с другим Коллекция. Самое простое - добавить это поведение через анонимный внутренний класс.

bagOfStuff = new HashSet(){
  @Override
  public boolean add(Object o) {
    boolean returnValue = super.add(o);
    if(returnValue && o instanceof Job)
    {
      Job job = ((Job)o);
      if(job.fooBar())
         otherBagOfStuff.add(job);
    }
    return returnValue;
  }
}

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

Ответ 8

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

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

Но вы должны знать, что когда вы используете 3 раза анонимный внутренний класс, который делает то же самое (например, удаляя "коллекцию" ), вы фактически создаете 3 новых класса в java PermGen.

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

Обратите внимание, что также почему синтаксис двойной фигурной скобки (анонимный внутренний класс с нестационарным блоком инициализации) иногда рассматривается как антипаттерн:

new ArrayList<String>() {{
     add("java");
     add("jsp");
     add("servlets");
  }}

Вы должны спросить людей, которые запрещают вам их использовать... ИМХО все зависит от контекста...

Ответ 9

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

Не используйте внутренний класс, если у вас есть опция.

Ответ 10

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

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

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

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

Ответ 11

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

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

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

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

Ответ 12

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

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

Ответ 13

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