InicioInicio BlogBlog portfolioCurriculum ProyectosProyectos videoLinks MyIpodMyIpod calendarContacto rssRSS

Introducción

En un post anterior tratamos lo que son las clases internas y definimos el uso mas común que se le puede dar a una clase interna, en este post trataremos el uso de una clase interna dentro de una interfaz y como instan ciarla fuera de la clase contenedora y la herencia de la clase contenedora y se puede “sobrescribir” una clase interna.

Alcance de las InnerClass

Como ya hemos visto las clases internas poseen grandes ventajas, como hemos visto las clases internas pueden ser declaradas como privadas, protegidas y publicas, al igual que los métodos las clases privadas solo son accesibles dentro de la clase, las privadas. A manera de referencia si se declara una clase interna como privada esta no podrá ser instanciada fuera de la clase, si es declarada como protected solo es accesible dentro del package de la clase contenedora y permite ser rescrita si la clase contenedora se le extiende además de ser instanciable en los hijos que hereden de la clase contenedora, en caso de accesible en todo parte del programa; y puede ser instanciada fuera de la clase contenedora.

Instancias de una clase interna fuera de la clase contenedora

Primero que todo existen dos maneras para instanciar explícitamente una clase interna, cada una tiene una ventaja y desventaja que definiremos más adelante. Para ambas soluciones la clase interna no puede estar contenida dentro de un método (obviamente se darán cuenta que la vida util de la clase no permite realizar la instancia explicita) y segundo la clase interna tiene que ser declara como publica. El código quedaría algo como así

package innerclasstwo;
public class Main {
 
    public class InternalClass
    {
        private String label;
        public InternalClass(String label)
        {
            this.label=label;
        }
        public void printLabel()
        {
  Main.this.printLabel(label);
         }
 
    private void printLabel(String label)
    {
         System.out.println(label);
    }
 
    public static void main(String[] args) {
        Main test=new Main();
        Main.InternalClass internal=  test.new InternalClass("hola mundo!!!");
        internal.printLabel();
    }
}

Nótese la instrucción “test.new InternalClass(String label);” como ven el new queda detrás de un punto y la instancia de Main, cabe notar que la clase tiene que ser instancia da por medio de una instancia de la clase contenedora, la clase interna tiene acceso a los métodos de la clase contenedora, esta es la ventaja primordial de esta solución

La otra solución es definir la clase como estática esto permitirá instan ciarla sin la necesidad de una instancia de la clase contenedora, pero para esto la clase interna declarada como final no tiene acceso a los métodos de la clase contenedora, Un miembro estático no puede referenciar a un elemento no estático. Pero en cambio no necesitaremos de un objeto para construir la clase interna. Un ejemplo seria algo asi

package innerclasstwo;
public class Main {
    public  static  class InternalClassFinal
    {
        private String label;
        public InternalClassFinal(String label)
        {
            this.label=label;
        }
        public void printLabel()
        {
           System.out.println(this.label);
        }
 
    }
 
    private void printLabel(String label)
    {
         System.out.println(label);
    }
    public static void main(String[] args) {
                Main.InternalClassFinal internalTwo= new Main.InternalClassFinal("hola mundo");
         internalTwo.printLabel();
    }
}

El uso de new es similar al usado con los packages, en este punto es diferente con el ejemplo anterior.

La desventaja de declarar la clase como final es que no se pueden acceder a ninguna propiedad o método de la clase contenedora aunque también sea estática no puede ser accedida por la clase interna, pero es independiente y puede ser instanciada sin una instancia de la clase contenedora

El primer método (NombreDelaClase instancia= nombredelobjeto.new ClaseInterna ()) se debe tener una instancia de la clase contenedora para realizar la instancia de la clase interna aunque podríamos declarar un objeto anónimo y hacer una instancia como de la siguiente manera

Main.InternalClass testThree=new Main().new InternalClass(" Hola Mundo");

Nótese que podríamos anidar clases internas (clases internas dentro de clases internas) y esta forma se vuelve engorrosa de analizar en caso de error o de modificación de código

Clases Internas dentro de una Interfaz o/y Clase Abstractas

Como conocerán las interfaces solo contienen la declaración de métodos y no el cuerpo de ellos, en el caso de incluir clases internas podemos desarrollar el cuerpo de una clase. Esto nos dará tres nuevas oportunidades, una es crear instancias de la interfase haciendo responsable a la clase interna, que la clase interna implemente la interfaz contenedora, o que esta sea un elemento “heredado” de la clase interna a las clases que la implementen. Para el siguiente ejemplo vamos a hacer una interfaz que nos permita probar las tres alternativas planteadas

En el apartado anterior notamos como instanciar clases internas explícitamente, como ya se imaginaran es posible construir clases internas dentro de interfaces y clases abstractas, obligatoriamente estas clases internas para ser instancia das. Una clase interna dentro de una interfase no puede ser declarada como protected o prívate, ya que en concepto todos los elementos de una interfaz son publicas

El código de la interfase a probar seria algo así

public interface Interface {
    public void SayHello();
 
    public static class FirstClass
    {
        public Interface getInstance()
        {
            return new Interface()
            {
                public void SayHello() {
                    System.out.println("hello i am a inner class");
                }
 
            };
        }
    }
    public static class SecondClass implements Interface
    {
        public void SayHello() {
           System.out.println ("Hello i am  another inner Class");
        }
    }
    public class ThirdClass
    {
 
        public void SayAnotherHello()
        {
            System.out.println("Hello i am  a simple inner class");
        }
    }
 
    public abstract class FourClass
    {
        public abstract void SayAnotherHello();
 
    }
}

FirstClass es una clase que retornara una instancia de Interface, SecondClass implementa la interfaz contenedora, ThirdClass es simplemente una clase publica y FourClass es una clase abstracta.

Ahora el main del ejemplo instanciando a FirstClass y SecondClass seria algo asi

public class Main
{
    public static void main(String[] args) {
        Interface inter=new Interface.FirstClass().getInstance();
        inter.SayHello();
        Interface interTwo= new  Interface.SecondClass();
        interTwo.SayHello();
 
    }
}

Claro esta si intentamos realizar una instancia de ThirdClass usando una instancia de FirstClass o SecondClass directamente, el codigo seria algo asi

Interface.ThirdClass innerClassFromInterface=new Interface.SecondClass().new ThirdClass() ;

Pero como Interface es una interfase y no un objecto el compilador nos dará el siguiente error

“source code - qualified new of static class”

Entonces acceder a una clase interna no estática de una interfaz no puede ser instanciada, se deberá usar una clase que implemente la internas para tener acceso a esta clase interna, inclusive la clase internas y estáticas declaradas dentro de la internas pueden hacer instancias de ThirdClass sin ningún problema, como ejemplo usaremos SecondClass y le incluiremos en método SayHello() una instancia de ThirdClass

  public static class SecondClass implements Interface
  {
        public void SayHello()
        {
           ThirdClass test=new ThirdClass();
           test.SayAnotherHello();
           System.out.println ("Hello i am  another inner Class");
        }
  }

Aun podemos hacer una prueba en una clase externa que implemente la clase abstracta (FourClass) y haga una instancia de ThirdClass

public class ClassAndInterface implements Interface {
 
    public void SayHello()
    {
        ThirdClass cla=new ThirdClass();
        cla.SayAnotherHello();
 
    }
 
    public void SaySecondHello()
    {
        new  FourClass()
        {
            @Override
            public void SayAnotherHello() {
               System.out.println("I am  a inner AbstractClass");
            }
 
        }.SayAnotherHello();
    }
 
    public FourClass getAbstractClass()
    {
        return new  FourClass()
        {
            @Override
            public void SayAnotherHello() {
               System.out.println("I am  a inner AbstractClass");
            }
 
        };
    }
 
}

Y a manera de prueba podemos incluir esta líneas en el main

        ClassAndInterface classAndInterface=new ClassAndInterface();
        classAndInterface.SayHello();
        Interface.FourClass abstractInnerClass =classAndInterface.getAbstractClass();
        abstractInnerClass.SayAnotherHello();

Las clases abstractas no se diferencian mucho a las interfaces, con respecto a lo que hemos estado hablando, pero la unica diferencia notable es que podemos hacer una instancia de una clase interna usando otra clase interna estática en otras palabras el compilador no nos dirá que es código incompilable, por ejemplo veamos esta clase abstracta usando el ejemplo anterior (SecondClass y ThirdClass)

public abstract class AbstractClass {
    public abstract void SayHello();
    public static class SecondClass extends AbstractClass
    {
        public void SayHello()
        {
           ThirdClass test=new ThirdClass();
           test.SayAnotherHello();
           System.out.println ("Hello i am  another abstract Class");
 
        }
    }
    public class ThirdClass
    {
 
        public void SayAnotherHello()
        {
            System.out.println("Hello i am  a simple abstract  class");
        }
    }
}

Podemos hacer una instancia de ThirdClass de forma reducida y explicita, en forma resumida será así la instancia:

AbstractClass.ThirdClass innerClassFromInterface=new AbstractClass.SecondClass().new ThirdClass() ;
 
innerClassFromInterface.SayAnotherHello();

En futuro y ultimo post trataremos Herencia de una clase contenedora

codigo de ejemplo


2 comentarios a “Introducción a InnerClass en Java II”  

  1. 1 Marcos Roberto

    Hola muchas gracias por aportar tus conocimientos, me ha sido de mucha utilidad…

  2. 2 admin

    muchas gracias marcos
    este blog lo tengo muy abandonado
    muy pronto lanzare un nuevo proyecto

Deja una respuesta



Categorías

Contacto

RSS Polygonize

Directorio de enlaces

Comparte este artículo

 
kajsdlkhsd