Зачем использовать метод локальных абстрактных внутренних классов - PullRequest
23 голосов
/ 29 апреля 2011

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

Например:

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

Есть ли ситуации, когда вы на самом деле используете это?*

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

Ответы [ 10 ]

12 голосов
/ 07 мая 2011

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

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

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

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
    }

}
9 голосов
/ 29 апреля 2011

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

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();
    }
}

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

7 голосов
/ 29 апреля 2011

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

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

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

  3. Ответ на ваш вопрос можно найти, изучив S 1 ∩ S 2

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


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

6 голосов
/ 10 мая 2011

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

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

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

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

1 голос
/ 29 апреля 2011

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

, который говорит

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

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

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

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

0 голосов
/ 15 февраля 2013

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

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

  @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;)

0 голосов
/ 13 мая 2011

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

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

Вот их пример кода:

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;
      }
   }
}
0 голосов
/ 12 мая 2011

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

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

0 голосов
/ 12 мая 2011
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);
    }
}

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

0 голосов
/ 08 мая 2011

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

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

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