Las clases anidadas en Java representan un concepto fundamental que, aunque no siempre es percibido como un nivel elevado de sofisticación, desempeña un papel crucial en la arquitectura de software. Esta idea consiste en declarar una clase dentro de otra, denominando a la clase exterior como la "clase exterior" y a la interior como la "clase anidada" o "nested class" en inglés. Esta estructura permite agrupar lógica relacionada de una manera que favorece la legibilidad y el mantenimiento del código.
¿Por qué usar clases anidadas?
Agrupación lógica: Permiten mantener juntas las clases que solo son relevadas dentro del contexto de una clase específica.
Mejora de la legibilidad: Facilitan la organización y simplificación del código, crucial en proyectos complejos.
Uso en proyectos avanzados: Son comunes en desarrollos con Java Enterprise Edition y Android, donde las bibliotecas suelen utilizarlas extensamente.
Tipos de clases anidadas
Las clases anidadas se dividen en dos categorías principales:
Clases estáticas (static nested classes):
Se declaran con la palabra clave static.
Funcionan como miembros estáticos de la clase que las contiene.
No requieren una instancia de la clase exterior para ser accesibles.
classOuterClass{staticclassStaticNestedClass{voiddisplay(){System.out.println("Dentro de StaticNestedClass");}}}
Clases no estáticas (clases inner):
No llevan la palabra clave static.
Necesitan una instancia de la clase exterior para su acceso.
Incluyen variantes como clases locales a métodos y clases anónimas.
classOuterClass{classInnerClass{voiddisplay(){System.out.println("Dentro de InnerClass");}}}
Detalle sobre cada tipo de clase
¿Cómo funcionan las clases estáticas?
Las clases estáticas en Java se asocian estrechamente con la palabra clave static. Esto les permite:
Ser llamadas directamente usando la clase exterior como punto de referencia.
Funcionar igual que métodos o atributos estáticos, de fácil acceso sin necesidad de instanciar la clase exterior.
Ejemplo de implementación:
classEnclosing{staticint x =10;staticclassStaticNested{voiddisplay(){System.out.println("Valor de x: "+ x);}}}publicclassMain{publicstaticvoidmain(String[] args){Enclosing.StaticNested nested =newEnclosing.StaticNested(); nested.display();}}
¿Qué son las clases inner?
Las clases inner, a diferencia de las estáticas, requieren de una instancia de la clase exterior para ser utilizadas. Permiten flexibilidad al interactuar con elementos no estáticos de la clase exterior.
Clases locales y anónimas
Clases Locales a Métodos: Se definen dentro de un método específico y su alcance están limitado al mismo.
classOuter{voidrun(){classLocal{voiddisplay(){System.out.println("Dentro de Local");}}Local local =newLocal(); local.display();}}
Clases Anónimas: Perfectas para implementaciones rápidas y específicas sin necesidad de una clase definida al 100%.
abstractclassAnonymous{abstractvoiddisplay();}publicclassMain{publicstaticvoidmain(String[] args){Anonymous anonymous =newAnonymous(){voiddisplay(){System.out.println("Implementación de clase anónima");}}; anonymous.display();}}
¿Cuándo deberías utilizarlas?
Clases estáticas: Útiles cuando tus métodos y variables son principalmente estáticos y no requieren acceso a instancias no estáticas de la clase exterior.
Clases anidadas no estáticas: Ideales cuando necesitas acceder y manipular atributos y métodos no estáticos de la clase exterior.
Las clases anidadas son más que un simple nivel de abstracción; son herramientas poderosas para organizar tu código y facilitar su mantenimiento. Es aconsejable limitarlas a una o dos por clase para evitar la complejidad extrema. ¡Ahora estás listo para experimentar y seguir integrándolas en tus proyectos!
Clases Anidadas en Java: Conceptos y Aplicaciones Prácticas
Se vuelve muy engorroso aplicar TODOS los estándares y TODOS los conceptos de clases de java, creo que lo mejor es utilizar las clases sin anidar o a lo mucho anidar 1 sola clase; se vuelve como la canción: "Hay un hoyo.. hay un hoyo en la orilla del mar... Una chicha, en bikini, una chica en bikini sentada en el hoyo en la orilla del mar..."
No entendí muy bien en la parte de las clases estáticas porque se creo un objeto de la clase estática para acceder a él cuando se supone que al ser estático no hace falta crear ningún objeto, sino que se puede acceder directamente a él.
Pero la utilidad de las clases anidadas cual es? no comprendo la lógica quien me explica? Que refleja una clase anidada una relación de composición ejemplo class carro { class motor{} }?
Supon que en tu caso el único que hace uso del Motor es el Carro, por ende, no quisieras tener tu clase Motor como una clase pública cualquiera, ya que eso viola el principio de encapsulamiento, si el único que hace uso del Motor es Carro, entonces el único que debería de tener acceso es Carro.
Depende de como se usen. Si la clase es muy pequeña y nadie más la va a usar o si el requerimiento de acceso a la clase es que únicamente otra clase determinada pueda hacerlo, las clases anidadas son un opción.
El principal uso de una clase anidada es ser utilizada dentro de la clase outter.
Terminan siendo una mala practica cuando son demasiadas.
es similar a los if() anidados, demasiados if() anidados puede ser demasiado complejo de leer, pero en ocasiones se necesita un if() anidado para una validación extra.
En mi percepcion la utilidad de las clases anidadas es tener un codigo legible, y controlado no siempre modularizar el codigo lo hace mas legible, y cuando me refiero a controlado ,es que al anidar le estoy dando una limitacion al scope de mi clase interna y sus metodos , obviamente mencionando los los modificadores de acceso
En cuanto a los distintos tipo de clases anidadas dejo mis ejemplos con sus apuntes de su funcionalidad
Inner Class
Al instanciar un objeto de mi clase interna tengo que llamar previamente mi clase externa
ClaseExterna.ClaseInterna Objeto
Clase Static Anidada
Utilizamos el objeto creado de la clase interior y con el punto llamamos especificamente el metodo de la clase interior
ObjetoClaseInterior.metodoClaseInterior
Varios tipos de clases andiadas
Pueden convivir varias clases anidadas y de diferente tipo
Clase dentro del metodo
En este caso el metodo que esta dentro de la clase interna, es el que mencionamos en el test ya que previamente se instancio un objeto de la clase local
No, las clases anidadas de hecho proveen de cohesión a nivel de clases. Normalmente no vas a utilizar clases anidadas en aplicaciones, casi que solo se usa cuando haces librerías o APIs reutilizables en otros proyectos. Pero bueno, un ejemplo practico es, Imagina que tienes una clase de un auto que es AutoYaris, este va a tener una clase interna llamado MotorYaris que extiende de una clase Motor. Esta clase interna hace que la instancia de AutoYaris camine, pero solamente vas a usar esa clase interna por que es especifica para los AutoYaris. Si vas a hacer AutoMazda3, vas a crearle su clase interna especifica, MotorMazda3, por que solamente la vas a usar en la clase Anfitriona, jamas en otra clase.
Como te digo, este concepto es casi que exclusivo para librerías que ya implementan patrones de diseño, un concepto puede que exista pero no necesariamente lo vas a usar (es mas, a veces el uso de clases anidadas puede que te haga codificar de mas, te lo digo por experiencia).
Pero esto hace que el programa no sea escalable, porque si limitas esa clase a que solo sea utilizada por su clase externa, y si en algún momento va a existir otra clase externa que utilize de esa clase. pum!
jejeje literalmente solo veo este concepto aplicado a librerías como dice el amigo Oscar.
Es un poco raro las clases anónimas porque una clase abstracta no podías declarar un objeto, pero aquí justamente dice "declarar un objeto de la clase abstracta" jajaja
Una clase abstracta no se puede instanciar, porque es justamente eso, una representación de algo demasiado abstracto, algo demasiado generalizado, y se necesita que una clase la extienda y le agregue una implementación especifica a sus metodos abstractos. Lo que haces con la clase anónima, es sacarle esa abstraccion o generalizacion agregandole una implementación a sus metodos de manera rapida, sin la necesidad de crear una clase nueva.
Honestamente no encuentro un caso de uso para implementar clases anidadas. Esto rompe completamente el paradigma orientado a objetos y sus fundamentos/principios.
Las clases anidadas te permiten agrupar lógicamente clases que solo se utilizan en un lugar, por lo tanto, esto aumenta el uso de la encapsulación y crea un código más fácil de leer y de mantener.
Una clase anidada no existe independientemente de su clase adjunta. Por lo tanto, el alcance de una clase anidada está limitado por su clase externa.
Una clase anidada también es miembro de su clase adjunta. También es posible declarar una clase anidada que es local a un bloque.
Como miembro de su clase adjunta, una clase anidada se puede declarar private, public, protected, o default (Leer sobre Modificadores de acceso).
Una clase anidada tiene acceso a los miembros, incluidos los miembros privados, de la clase en la que está anidado. Sin embargo, lo inverso no es verdadero, es decir, la clase adjunta no tiene acceso a los miembros de la clase anidada.
Hay dos tipos generales de clases anidadas: las que están precedidas por el modificador static (static nested class) y las que no lo están (inner class).
La explicación de los tipos de clases para las anidaciones es posible expresarlas en sentido de patrones? Como por ejemplo un singleton para una clase con un constructor privado y un unico metodo de acceso static getInstance()?
classOuterClass{ int x =10;classInnerClass{ int y =5;}}publicclassMyMainClass{publicstaticvoidmain(String[] args){OuterClass myOuter =newOuterClass();OuterClass.InnerClass myInner = myOuter.newInnerClass();System.out.println(myInner.y+ myOuter.x);}}```
Si una clase estática está anidada dentro de otra clase, sigue siendo una clase estática y no se puede instanciar directamente. Sin embargo, la clase externa puede crear instancias de la clase interna estática.
Cuando se declara una clase estática dentro de otra clase, se establece una relación de pertenencia, pero la clase interna estática no depende de una instancia de la clase externa. Esto significa que la clase interna estática se puede utilizar sin necesidad de crear una instancia de la clase externa.
Para acceder a la clase estática anidada, se utiliza la sintaxis ClaseExterna.ClaseInterna. Por ejemplo, si tienes una clase llamada ClaseExterna que contiene una clase estática anidada llamada ClaseInterna, puedes acceder a la clase interna de la siguiente manera:
java
Copy code
ClaseExterna.ClaseInterna instancia = new ClaseExterna.ClaseInterna();
Es importante destacar que la clase interna estática no puede acceder a los miembros no estáticos de la clase externa, ya que no tiene una referencia a una instancia específica de la clase externa. Solo puede acceder a los miembros estáticos de la clase externa.
En resumen, una clase estática anidada sigue siendo una clase estática y no se puede instanciar directamente. Se accede a ella utilizando la sintaxis ClaseExterna.ClaseInterna, y la clase externa puede crear instancias de la clase interna estática.
Can an inner class access the outter class attributes?
Hice un par de pruebas de conceptos por si a alguien le sirve. Use inner class, static nested class y method inner class.
Este es el repo:
y para que tengan una idea así esta mi main:
package ar.com.martinjm.practice;import ar.com.martinjm.practice.nestedclasses.OuterClass;publicclassApplication{publicstaticvoidmain(String args[]){System.out.println("nested classes");System.out.println("");//Test StaticNestedClass with static method and non static methodsOuterClass.StaticNestedClass.hereIAm();OuterClass.StaticNestedClass staticNestedClass =newOuterClass.StaticNestedClass(); staticNestedClass.hereIam();//Test Inner classOuterClass outerClass =newOuterClass();OuterClass.InnerClass innerClass = outerClass.newInnerClass(); innerClass.hereIam();//Test class in a methodOuterClass.hereIAm();}}````Saludos:D
En este caso Ann creó un método no estático (el método run) dentro de la clase estática. Algo cómo esto:
Efectivamente podemos acceder a la clase estática sin necesidad de instanciarla, pero los métodos internos de esta clase “StaticNested” no son estáticos. Es decir, para poder “ejecutarAlgo” dentro de la clase “StaticNested” sin necesidad de instanciar un objecto de la clase, este método deberá ser static también
Lo mismo sucede con los atributos. Para poder utilizarlos sin instanciar la clase se necesitan declararlos como static también.
Espero haya quedado claro 😃… si tienes otra consulta no dudes en preguntar 😉
Hola ivanyovera, yo diría que es correcta tu conclusión, pues de hecho el código que Ann nos presenta en el ejemplo precisamente nos lo está demostrando.
Además yo hice una variación a la clase externa que Ann nos da y en vez de el Test le coloque un metodo publico que accediera a la clase privada interna y a su método privado interno desde la clase Main que no solo es externa sino que esta en otro paquete también y me funcionó ok.
Acá el ejemplo de la implementación que probé, fijate que tanto la clase interna como su método los puse private:
OuterClass
package com.erosennin.amazonviewer.challenges;publicclassOuterClass{privatestaticclassInnerClass{privatevoidrun(){System.out.println("InnerClass Run Method");}}publicvoidrun(){OuterClass.InnerClass innerClass =newInnerClass(); innerClass.run();}}