Why use method local abstract inner classes

后端 未结 10 1755
名媛妹妹
名媛妹妹 2021-02-05 04:45

One of the legal modifiers you can use with method local inner classes is abstract.

For example:

public class Outer {
    public void method(){
        a         


        
相关标签:
10条回答
  • 2021-02-05 05:08

    The are some invalid assumptions in the original question. That something is legal/valid Java doesn't mean that it is something that you need to use, or need to know.

    I can't recall that the SCJP contains odd corner case questions.

    I tried to come up with a case where I would have used an abstract class declared in a method, but everything looks very odd, and reeks of bad design. Here's however a code example that I came up with (still bad code design 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
        }
    
    }
    
    0 讨论(0)
  • 2021-02-05 05:09

    You can get the use here http://java-questions.com/InnerClass_interview_questions.html

    which says

    The inner class declared inside the method is called method local inner class. Method local inner class can only be declared as final or abstract. Method local class can only access global variables or method local variables if declared as final

    ie You can declare the static variables in the inner call and use them in the methods.

    EDIT: Why abstract:

    Because if you dont want to create the objects of the inner class. If you create the object in the method then it will be stored in the heap and it is not freed even if the method execution completes as there might be an external reference for this object when it is returned from the method.

    So it depends on whether you want to create an instance or not. If you want to create then use final modifier.

    0 讨论(0)
  • 2021-02-05 05:12
    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);
        }
    }
    

    You can use it like this.

    0 讨论(0)
  • 2021-02-05 05:14

    Check out the section titled "Hierarchies of Inner Classes" on this page.

    The gist is that you can treat the inner class as just another abstract member that needs to be overridden/implemented. I don't necessarily agree with it (I would probably just define the inner class separately), but I've seen things like this in the wild.

    Here's their example code:

    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 讨论(0)
  • 2021-02-05 05:16

    I think it can be useful to reduce the scope of methods in certain conditions.

    For exemple, I use it in unit tests. Sometimes you need an utility method to reduce the verbosity of a test. But this utility method may be related to the current test dataset, and can't be reused outside of this test.

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

    In this real-life exemple, I could have done a regular inner class, but someone could have been tempted to reuse it in other tests, while it was not designed to.

    By the way, you will notice the ability to "capture" the dataset build in the test directly inside the utility class. Using a regular inner class, it couldn't work without creating the test specific dataset outside the test too... so you end up with a lot of things shared with other tests, while they are used (should be used) by only one.


    In the end, I don't think a feature permitting to reduce the visibility is useless.

    You can build a perfectly working application without using encapsulation at all, and can argue the same thing, saying the private modifier is useless...

    But yes, the private modifier is certainly more useful than method local innerclasses ;)

    0 讨论(0)
  • 2021-02-05 05:18

    the only real use I can imagine is for nodes in a data structure

    that way you can differentiate methods from sentinel nodes and normal data nodes which can be really handy in recursive algorithms and you don't have to null check each time

    0 讨论(0)
提交回复
热议问题