2011-04-29 11 views
23

Uno de los modificadores legales que puede usar con las clases internas locales del método es abstracto.Por qué usar el método de clases internas abstractas locales

Por ejemplo:

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

¿Hay alguna situación en la que usted realmente usar esto?

Tienes que saber esto para el examen SCJP.

Respuesta

12

El son algunos supuestos no válidos en la pregunta original. Que algo sea legal/válido Java no significa que sea algo que necesite usar o necesite saber.

No puedo recordar que el SCJP contiene preguntas de casos de esquina impares.

Traté de encontrar un caso en el que hubiera usado una clase abstracta declarada en un método, pero todo parece muy extraño y apesta a mal diseño. Aquí es sin embargo un ejemplo de código que se me ocurrió (código sigue siendo malo en mi humilde opinión diseño)

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 
    } 

} 
+1

+1 Parece el mejor ejemplo. Todavía es bastante malo, ya que el método es demasiado extenso y el comportamiento debería colocarse mejor en la enumeración. – maaartinus

+0

Estoy totalmente de acuerdo, el diseño huele a lo grande, y esa es probablemente la razón por la que nunca he visto a nadie hacer eso durante mis 15 años de programación en Java. – Kaj

+0

De acuerdo. Además, para los programadores malos es demasiado alto y los buenos lo evitan. – maaartinus

1

, usted puede obtener el uso aquí http://java-questions.com/InnerClass_interview_questions.html

que dice

La clase interna declarada dentro del método se denomina método de clase interna local. Método La clase interna local solo se puede declarar como final o abstracta. Método La clase local solo puede acceder a las variables globales o a las variables locales del método si se declara como final

es decir, puede declarar las variables estáticas en la llamada interna y usarlas en los métodos.

EDIT: ¿Por abstracta:

Porque si no desea crear los objetos de la clase interna. Si crea el objeto en el método, se almacenará en el montón y no se liberará, incluso si la ejecución del método finaliza, ya que puede haber una referencia externa para este objeto cuando se devuelve desde el método.

Por lo tanto, depende de si desea crear una instancia o no. Si desea crear, utilice el modificador final.

+0

Eso no explica por qué la clase interna en el ejemplo es 'abstracta' –

+1

No tiene que declarar un resumen de clase para no crear una instancia. La parte importante es que quieres subclasificarla y posiblemente con diferentes implementaciones. –

7

¿Hay alguna situación en la que realmente usaría esto?

  1. Sea S denotar todas las situaciones en las que necesita una clase abstracta.

  2. Let S indican todas las situaciones en las que necesita una clase local.

  3. La respuesta a su pregunta se puede encontrar mediante el examen de S ∩ S

preguntas relacionadas:


Aclaración: Mi punto es que las dos funciones (clases abstractas y clases locales) son dos características completamente ortogonales de la lengua.Comprender cuándo cada función es útil es la clave para comprender cuándo ambas son útiles al mismo tiempo.

+3

-1 No veo ningún valor real aquí, de esta manera usted podría responder casi cualquier pregunta sin proporcionar ninguna información. Además, la intersección parece estar bastante vacía. – maaartinus

+3

Si encuentra la intersección vacía, creo que la pregunta ha sido respondida. (Clarificado mi respuesta un poco.) – aioobe

+0

Eso es mejor. En realidad, no creo que tu respuesta sea mala, es solo que en mi humilde opinión no es lo suficientemente buena para tantos votos al alza (al menos en comparación con las respuestas mucho más concretas). +1 al comentario (también para mencionar ortogonalidad). – maaartinus

9

me ocurre sólo en este caso

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

pero no puedo imaginar usos reales

0

el único uso real que puedo imaginar es para los nodos en una estructura de datos

de esa manera se puede diferenciar los métodos de nodos centinela y nodos de datos normales que pueden ser realmente útiles en algoritmos recursivos y no tiene que anular cada vez

+0

Seguir definiendo una jerarquía de clases en un método no parece ser tan bueno ... –

6

En mi humilde opinión, esta función NO tiene un uso real. Hay un par de posibles abusos, pero hay muchas otras maneras de escribir código incorrecto, no necesita aprender este. : D

Siempre que intente utilizar una clase local de método abstracto, debe definir al menos dos clases internas de método concreto. Esto significa que terminas con un método que contiene al menos tres clases, el método es bastante largo y es un estilo bastante malo.

Tienes que saber esto para el examen SCJP.

Realmente espero que no. Las clases internas locales de método ya son lo suficientemente inútiles como para ser consideradas un caso de esquina (debe comprenderlas, pero probablemente nunca las use).

En mi humilde opinión, una persona que pregunta esto en un examen mal entendido Java mal. No puede haber modificadores de accesibilidad en una clase local dado que (al carecer de literales de método) no se puede acceder a la clase desde el exterior de todos modos. Puede haber modificadores abstract y final, ya que no hay ninguna razón para prohibirlos. Hay buenas razones para permitirles: orthogonality y Principle of least astonishment.

+0

La única razón es que está en el SCJP para que sepa qué modificadores se pueden aplicar al método de clases internas locales. Entonces, por ejemplo, si una clase tiene un modificador privado, debe saber que no se compilará. – Gordon

+0

@Gordon: Tal vez ..., pero poner un modificador en una clase de método local no tiene sentido (ya que no se puede usar al aire libre de todos modos). Saber que no puedes hacerlo no te ayuda, ya que debes estar bastante equivocado antes de intentarlo. Saber qué hace el compilador en casos de esquina extraños es inútil, o tiene el compilador y lo prueba o no tiene el compilador y no necesita saberlo. * Hay muchas cosas complicadas en Java que es mucho más útil saber. * – maaartinus

+1

Lamentablemente, con el examen SCJP tienes que actuar como compilador.Hay una cantidad ridícula de cosas que debe saber que se recogerán inmediatamente un complier. – Gordon

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

Puede usarlo así.

0

No, no hay un buen uso para las clases abstractas (o clases en general) dentro de los métodos.

Tendría sentido si solo ese método en particular necesitaría esa clase en particular y también lo implementaría. En realidad, tener esa situación tal vez ocurra una vez en billones de métodos que escribes.

0

Consulte la sección titulada "Jerarquías de clases internas" en this page.

Lo esencial es que puede tratar la clase interna como simplemente otro miembro abstracto que debe ser reemplazado/implementado.No necesariamente estoy de acuerdo (probablemente definiría la clase interna por separado), pero he visto cosas como esta en la naturaleza.

Aquí es su código ejemplo:

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

Creo que puede ser útil para reducir el alcance de los métodos en ciertas condiciones.

Por ejemplo, lo uso en pruebas unitarias. Algunas veces necesita un método de utilidad para reducir la verbosidad de una prueba. Pero este método de utilidad puede estar relacionado con el conjunto de datos de prueba actual y no puede reutilizarse fuera de esta prueba.

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

En este exemple de la vida real, que podría haber hecho una clase interna regular, pero alguien podría haber tenido la tentación de volver a utilizarlo en otras pruebas, mientras que no fue diseñado para.

Por cierto, notará la capacidad de "capturar" la compilación del conjunto de datos en la prueba directamente dentro de la clase de utilidad. Usar una clase interna regular, no podría funcionar sin crear el conjunto de datos específico de la prueba fuera de la prueba también ... por lo que terminas con muchas cosas compartidas con otras pruebas, mientras se usan (deberían usarse) con solo una .


Al final, no creo que una característica que permite reducir la visibilidad es inútil.

Se puede construir una aplicación perfecta eficacia sin necesidad de utilizar la encapsulación en absoluto, y se puede discutir lo mismo, diciendo que el modificador privada es inútil ...

Pero sí, el modificador privada es sin duda más útil que el método local innerclasses;)

Cuestiones relacionadas