sábado, 14 de enero de 2012

Clases anidadas

votar
   En Java, cuando una clase se complica demasiado, o cuando necesita métodos de otra clase, a veces es conveniente utilizar clases dentro de otras clases, o dentro de interfaces, antes que escribirlas varias páginas más allá en el código. Estas clases se llaman clases anidadas y pueden ser de dos tipos:
  • Estáticas
  • Internas
   A su vez, las clases internas pueden ser:
  • Miembro
  • Locales
  • Anónimas
   Vamos a ver con más detalle estas clases, comenzando por las estáticas.
   Las clases anidadas estáticas son muy sencillas de declarar:

   class Externa{
      static class AnidEstatic{
          //código
      }
   }

   Una clase anidada estática puede acceder directamente  a los métodos y atributos estáticos de la en la que está inmersa, incluido los privados, pero no a los no estáticos (es lo mismo que ocurre con los métodos estáticos). Para acceder a estos necesita hacerlo a través de una instancia de la clase:

   class Externa{
      int i;
      static class AnidEstatic{
         Externa e = new Externa( );
         {
            e.i = 8; //acceso a un miembro variable a través de una instancia de la clase externa
          }
      }
   }

   El nombre completo de una clase estática anidada incluye el de la clase externa, así que para crear una instancia de esta clase desde fuera de la clase contenedora, tendríamos que crear escribir lo siguiente:

   Externa.AnidEstatic ae = new Externa.AnidEstatic( );

   Pasemos ahora a las clases internas, comenzando por las del tipo miembro. Una clase interna miembro se llama así porque es un miembro más de la clase que la contiene y tiene por lo tanto acceso a cualquier otro miembro, incluso los privados. La clase externa debe declarar una instancia de la clase interna antes de poder invocar sus métodos o utilizar sus atributos.
   Para declarar una clase interna miembro, hacemos exactamente lo mismo que con una clase anidada estática, solo que sin el static delante:

   class Externa{
      class InMi{
         //código
      }
   }

   Al compilar una clase interna miembro, se crean dos archivos distintos:

      Externa.class
      Externa$InMi.class

   Al contrario que la clase interna miembro, una clase interna local no es un miembro de la clase externa. Es declarada dentro de un bloque, normalmente un método, y no es accesible fuera del mismo, pero se puede crear un objeto de ella y utilizarlo como referencia.
   
   void método( ){
      class InLo{
         //código
      }
      InLo il = new InLo( );
      nuevoMétodo(il);
   }

   Una clase interna local no puede utilizar las variables locales del método en el que está alojada, a no ser que estén marcadas como final, es decir, que no puedan cambiar, ya que la vida de una instancia de la clase interna puede ser mayor que la del método en la que dicha clase fue creada y las variables locales solo pueden vivir mientras viva su método.

   Veamos finalmente las clases internas anónimas, así llamadas porque son declaradas sin ningún nombre de clase.
   Las clases anónimas pueden ser declaradas dentro de un método e incluso dentro del argumento de un método. Esto puede hacerse porque se declaran e instancian en una única expresión.

   class Ejemplo{
      public void ej( ){
         System.out.println("clase Ejemplo");
      }
   }
   class Externa{
      Ejemplo ej = new Ejemplo( ){ //esto no es una referencia a una instancia de Ejemplo, sino una referencia 
                                                    //a una subclase de Ejemplo (anónima)
         public void ej( ){
            System.out.println("clase Ejemplo anónima");
         }
      }; //¡acaba con un punto y coma!
   }

   Las clases anónimas son tratadas por el compilador como si fuesen clases locales internas, por lo tanto, sólo pueden acceder a las variables del método en el que están inmersas si éstas están marcadas como final.









4 comentarios: