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

Зачем использовать локальные абстрактные внутренние классы метода

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

Например:

public class Outer {
    public void method(){
        abstract class Inner{
        }
    }
}

Есть ли какая-нибудь ситуация, когда вы действительно используете это?

Вы должны знать это для экзамена SCJP.

4b9b3361

Ответ 1

Вот некоторые недопустимые предположения в исходном вопросе. Это что-то юридическое/допустимое. Java не означает, что это то, что вам нужно использовать или нужно знать.

Я не могу вспомнить, что SCJP содержит вопросы с нечетным углом.

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

public class BatchExecutor {

    public static enum ResultNotification {
        JMS,
        MAIL
    };

    public Runnable createRunnable(ResultNotification type) {
        abstract class Prototype implements Runnable {
            public void run() {
                performBusinessLogic();
                publishResult();
            }

            abstract void publishResult();
        }

        switch (type) {
            case JMS: {
                return new Prototype() {
                    void publishResult() {
                        //Post result to JMS
                    }
                };
            }
            case MAIL: {
                return new Prototype() {
                    void publishResult() {
                        //Post result to MAIL
                    }
                };
            }
        }
        return null;
    }

    private void performBusinessLogic() {
        //Some business logic
    }

}

Ответ 2

Я могу думать только в этом случае

class Outer {
    public void method() {
        abstract class A {
            void bar(){}
            abstract void foo();
        }
        class B extends A {
            @Override
            void foo() {
            }
        }
        final class C extends A {
            @Override
            void foo() {
            }
        }
        A a1 = new B();
        A a2 = new C();
    }
}

Но я не могу представить себе реальное использование

Ответ 3

Есть ли какая-нибудь ситуация, когда вы действительно используете это?

  • Пусть S 1 обозначает все ситуации, в которых вам нужен абстрактный класс.

  • Пусть S 2 обозначает все ситуации, в которых вам нужен локальный класс.

  • Ответ на ваш вопрос можно найти, исследуя S 1 ∩ S 2

Похожие вопросы:


Разъяснение: Я хочу сказать, что две функции (абстрактные классы и локальные классы) - две полностью ортогональные функции языка. Понимание того, когда каждая функция полезна, является ключом к пониманию, когда они одновременно полезны в одно и то же время.

Ответ 4

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

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

Вы должны знать это для экзамена SCJP.

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

ИМХО, человек, просящий это на экзамене, неправильно понял Java. Модификаторы доступности не могут быть в локальном классе, поскольку (не имея литералов метода), к тому же класс не может быть доступен извне. Могут быть модификаторы abstract и final, так как нет причин их запрещать. Для этого есть веские причины: orthogonality и Принцип наименьшего удивление.

Ответ 5

Вы можете использовать здесь http://java-questions.com/InnerClass_interview_questions.html

в котором говорится

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

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

EDIT: почему реферат:

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

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

Ответ 6

единственное реальное использование, которое я могу себе представить, - это узлы в структуре данных

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

Ответ 7

package dto;

public class Outer {

    public void method(int x, int y){
        abstract class Inner{
            abstract void performAction(int x,int y);
        }
        class InnnerA extends Inner{

            @Override
            void performAction(int x,int y) {
                int z =x+y;
                System.out.println("addition :" + z);

            }

        }
        class InnnerB extends Inner{

            @Override
            void performAction(int x,int y) {
                System.out.println("multiply :"+x*y);

            }

        }
        Inner inner1 = new InnnerA();
        inner1.performAction(x,y);
        Inner inner2 = new InnnerB();
        inner2.performAction(x,y);
    }
    public static void main(String args[]){
        Outer outer = new Outer();
        outer.method(10,20);
    }
}

Вы можете использовать его так.

Ответ 8

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

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

Ответ 9

Ознакомьтесь с разделом "Иерархии внутренних классов" на этой странице.

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

Вот их примерный код:

public abstract class BasicMonitorScreen {
   private Dimension resolution;

   public BasicMonitorScreen(final Dimension resolution) {
      this.resolution = resolution;
   }

   public Dimension getResolution( ) {
      return this.resolution;
   }

   protected abstract class PixelPoint {
      private int x;

      private int y;

      public PixelPoint(final int x, final int y) {
         this.x = x;
         this.y = y;
      }

      public int getX( ) {
         return x;
      }

      public int getY( ) {
         return y;
      }
   }
}

public class ColorMonitorScreen extends BasicMonitorScreen {
   public ColorMonitorScreen(final Dimension resolution) {
      super(resolution);
   }

   protected class ColorPixelPoint extends PixelPoint {
      private Color color;
      public ColorPixelPoint(final int x, final int y, final Color color) {
         super(x, y);
         this.color = color;
      }

      public Color getColor( ) {
         return this.color;
      }
   }
}

Ответ 10

Я думаю, что может быть полезно уменьшить объем методов в определенных условиях.

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

  @Test
  public void facetting_is_impacted_by_filtering() {
    // given
    String userId = "cd01d6b08bc29b012789ff0d05f8e8f1";
    DocumentSolrClient client = solrClientsHolder.getDocumentClient(userId);
    //
    final SolrDocument doc1 = createDocument(userId);
    doc1.setAuthorName("AuthorName1");
    doc1.setType("Type1");
    doc1.setUserTags(Arrays.asList("UserTag1", "UserTag1bis","UserTag1bisbis"));
    doc1.setSenderTags(Arrays.asList("SenderTag1", "SenderTag1bis"));
    doc1.setCreationDate( new Date(EnumDateRange.CURRENT_DAY.getBegin().getTime()+1000) );
    doc1.setLocation(DocumentLocation.INBOX);
    client.index(doc1);
    //
    final SolrDocument doc2 = createDocument(userId);
    doc2.setAuthorName("AuthorName2");
    doc2.setType("Type2");
    doc2.setUserTags(Arrays.asList("UserTag2"));
    doc2.setSenderTags(Arrays.asList("SenderTag2"));
    doc2.setCreationDate( new Date(1000) ); // cree il y a tres longtemps
    doc2.setLocation(DocumentLocation.SAFE);
    client.index(doc2);
    //
    final List<DateRange> facettedRanges = Arrays.<DateRange>asList(
            EnumDateRange.CURRENT_DAY,
            EnumDateRange.CURRENT_YEAR,
            EnumDateRange.BEFORE_CURRENT_YEAR
    );
    class TestUtils {
      ApiSearchRequest baseFacettingRequest(String userId) {
        ApiSearchRequest req = new ApiSearchRequest(userId);
        req.setDocumentTypeFacets(true);
        req.setSenderNameFacets(true);
        req.setSenderTagsFacets(true);
        req.setUserTagsFacets(true);
        req.addDateCreationFacets(facettedRanges);
        return req;
      }
      void assertDoc1FacettingResult(ApiSearchResponse res) {
        assertThat(res.getDocuments().size()).isEqualTo(1);
        assertThat(res.getDocumentTypeFacets().get().getCounts()).hasSize(1);
        assertThat(res.getSenderNameFacets().get().getCounts()).hasSize(1);
        assertThat(res.getSenderTagsFacets().get().getCounts()).hasSize(2);
        assertThat(res.getUserTagsFacets().get().getCounts()).hasSize(3);
        assertThat(res.getDateCreationFacets().get().getCounts()).isEqualTo( computeExpectedDateFacettingResult( Arrays.asList(doc1),facettedRanges) );
      }
      void assertDoc2FacettingResult(ApiSearchResponse res) {
        assertThat(res.getDocuments().size()).isEqualTo(1);
        assertThat(res.getDocumentTypeFacets().get().getCounts()).hasSize(1);
        assertThat(res.getSenderNameFacets().get().getCounts()).hasSize(1);
        assertThat(res.getSenderTagsFacets().get().getCounts()).hasSize(1);
        assertThat(res.getUserTagsFacets().get().getCounts()).hasSize(1);
        assertThat(res.getDateCreationFacets().get().getCounts()).isEqualTo( computeExpectedDateFacettingResult( Arrays.asList(doc2),facettedRanges) );
      }
    }
    TestUtils utils = new TestUtils();
    /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    // when
    ApiSearchRequest req = utils.baseFacettingRequest(userId);
    ApiSearchResponse res = documentSearchService.search(req);
    // then
    assertThat(res.getDocuments().size()).isEqualTo(2);
    assertThat(res.getDocumentTypeFacets().get().getCounts()).hasSize(2);
    assertThat(res.getSenderNameFacets().get().getCounts()).hasSize(2);
    assertThat(res.getSenderTagsFacets().get().getCounts()).hasSize(3);
    assertThat(res.getUserTagsFacets().get().getCounts()).hasSize(4);
    assertThat(res.getDateCreationFacets().get().getCounts()).isEqualTo( computeExpectedDateFacettingResult( Arrays.asList(doc1,doc2),facettedRanges) );
    /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    // when
    req = utils.baseFacettingRequest(userId);
    req.addLocation(DocumentLocation.SAFE);
    res = documentSearchService.search(req);
    // then
    utils.assertDoc2FacettingResult(res);
    /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    // when
    req = utils.baseFacettingRequest(userId);
    req.addUserTag("UserTag1");
    res = documentSearchService.search(req);
    // then
    utils.assertDoc1FacettingResult(res);
    /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    // when
    req = utils.baseFacettingRequest(userId);
    req.addSenderTag("SenderTag2");
    res = documentSearchService.search(req);
    // then
    utils.assertDoc2FacettingResult(res);
    /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    // when
    req = utils.baseFacettingRequest(userId);
    req.setDocumentType("Type1");
    res = documentSearchService.search(req);
    // then
    utils.assertDoc1FacettingResult(res);
  }

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

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


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

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

Но да, частный модификатор, безусловно, более полезен, чем метод local innerclasses;)