La clase interna de Java se define dentro del cuerpo de otra clase. La clase interna de Java puede declararse como privada, pública, protegida o con acceso predeterminado, mientras que una clase externa solo puede tener acceso público o predeterminado. Las clases anidadas en Java se dividen en dos tipos.
-
Clase anidada estática
Si la clase anidada es estática, se llama clase anidada estática. Las clases anidadas estáticas solo pueden acceder a miembros estáticos de la clase externa. Una clase anidada estática es igual que cualquier otra clase de nivel superior y está anidada solo por conveniencia de empaquetado. Se puede crear un objeto de clase estática con la siguiente declaración.
OuterClass.StaticNestedClass objetoAnidado = new OuterClass.StaticNestedClass();
-
Clase interna de Java
Cualquier clase anidada no estática se conoce como clase interna en Java. La clase interna de Java está asociada con el objeto de la clase y puede acceder a todas las variables y métodos de la clase externa. Dado que las clases internas están asociadas con la instancia, no podemos tener variables estáticas en ellas. El objeto de la clase interna de Java forma parte del objeto de la clase externa y para crear una instancia de la clase interna, primero necesitamos crear una instancia de la clase externa. La clase interna de Java se puede instanciar así;
OuterClass outerObject = new OuterClass(); OuterClass.InnerClass innerObject = outerObject.new InnerClass();
Hay dos tipos especiales de clases internas en Java.
-
clase interna local
Si una clase está definida dentro del cuerpo de un método, se conoce como clase interna local. Dado que la clase interna local no está asociada con un Objeto, no podemos usar modificadores de acceso private, public o protected con ella. Los únicos modificadores permitidos son abstract o final. Una clase interna local puede acceder a todos los miembros de la clase que la envuelve y a las variables locales finales en el ámbito en que está definida. Además, también puede acceder a una variable local no final del método en el que está definida, pero no puede modificarlas. Por lo tanto, si intentas imprimir el valor de una variable local no final, se permitirá, pero si intentas cambiar su valor desde dentro del método de la clase interna local, obtendrás un error de tiempo de compilación. Se puede definir una clase interna local de la siguiente manera:
package com.journaldev.innerclasses; public class MainClass { private String s_main_class; public void print() { String s_print_method = ""; // clase interna local dentro del método class Logger { // capaz de acceder a las variables de la clase que la envuelve String name = s_main_class; // capaz de acceder a variables del método no final String name1 = s_print_method; public void foo() { String name1 = s_print_method; // El código siguiente generará un error de tiempo de compilación: // La variable local s_print_method definida en un ámbito exterior debe ser final o efectivamente final // s_print_method= ":"; } } // instanciar clase interna local en el método para usarla Logger logger = new Logger(); } }
También podemos definir una clase interna local dentro de cualquier bloque, como un bloque estático, un bloque if-else, etc. Sin embargo, en este caso, el ámbito de la clase será muy limitado.
public class MainClass { static { class Foo { } Foo f = new Foo(); } public void bar() { if(1 < 2) { class Test { } Test t1 = new Test(); } // Lo siguiente generará un error debido al ámbito de la clase //Test t = new Test(); //Foo f = new Foo(); } }
-
clase interna anónima
Una clase interna local sin nombre se conoce como clase interna anónima. Una clase anónima se define e instancia en una única declaración. Las clases internas anónimas siempre extienden una clase o implementan una interfaz. Dado que una clase anónima no tiene nombre, no es posible definir un constructor para una clase anónima. Las clases internas anónimas son accesibles solo en el punto donde se definen. Es un poco difícil definir cómo crear una clase interna anónima, veremos su uso en tiempo real en el programa de prueba a continuación.
Aquí hay una clase java que muestra cómo definir una clase interna java, una clase interna estática, una clase interna local y una clase interna anónima. OuterClass.java
package com.journaldev.nested;
import java.io.File;
import java.io.FilenameFilter;
public class OuterClass {
private static String name = "OuterClass";
private int i;
protected int j;
int k;
public int l;
//Constructor de OuterClass
public OuterClass(int i, int j, int k, int l) {
this.i = i;
this.j = j;
this.k = k;
this.l = l;
}
public int getI() {
return this.i;
}
//Clase anidada estática, puede acceder a las variables/métodos estáticos de OuterClass
static class StaticNestedClass {
private int a;
protected int b;
int c;
public int d;
public int getA() {
return this.a;
}
public String getName() {
return name;
}
}
//Clase interna, no estática y puede acceder a todas las variables/métodos de la clase externa
class InnerClass {
private int w;
protected int x;
int y;
public int z;
public int getW() {
return this.w;
}
public void setValues() {
this.w = i;
this.x = j;
this.y = k;
this.z = l;
}
@Override
public String toString() {
return "w=" + w + ":x=" + x + ":y=" + y + ":z=" + z;
}
public String getName() {
return name;
}
}
//Clase interna local
public void print(String initial) {
//Clase interna local inside the method
class Logger {
String name;
public Logger(String name) {
this.name = name;
}
public void log(String str) {
System.out.println(this.name + ": " + str);
}
}
Logger logger = new Logger(initial);
logger.log(name);
logger.log("" + this.i);
logger.log("" + this.j);
logger.log("" + this.k);
logger.log("" + this.l);
}
//Clase interna anónima
public String[] getFilesInDir(String dir, final String ext) {
File file = new File(dir);
//Clase interna anónima implementing FilenameFilter interface
String[] filesList = file.list(new FilenameFilter() {
@Override
public boolean accept(File dir, String name) {
return name.endsWith(ext);
}
});
return filesList;
}
}
Aquí está el programa de prueba que muestra cómo instanciar y usar la clase interna en Java. InnerClassTest.java
package com.journaldev.nested;
import java.util.Arrays;
//Las clases anidadas se pueden usar en la importación para una fácil instanciación
import com.journaldev.nested.OuterClass.InnerClass;
import com.journaldev.nested.OuterClass.StaticNestedClass;
public class InnerClassTest {
public static void main(String[] args) {
OuterClass outer = new OuterClass(1,2,3,4);
//Ejemplo de clases anidadas estáticas
StaticNestedClass staticNestedClass = new StaticNestedClass();
StaticNestedClass staticNestedClass1 = new StaticNestedClass();
System.out.println(staticNestedClass.getName());
staticNestedClass.d=10;
System.out.println(staticNestedClass.d);
System.out.println(staticNestedClass1.d);
//Ejemplo de clase interna
InnerClass innerClass = outer.new InnerClass();
System.out.println(innerClass.getName());
System.out.println(innerClass);
innerClass.setValues();
System.out.println(innerClass);
//Llamando a un método usando una clase interna local
outer.print("Outer");
//Llamando a un método usando una clase interna anónima
System.out.println(Arrays.toString(outer.getFilesInDir("src/com/journaldev/nested", ".java")));
System.out.println(Arrays.toString(outer.getFilesInDir("bin/com/journaldev/nested", ".class")));
}
}
Aquí está la salida del programa de ejemplo de clase interna en Java anterior.
OuterClass
10
0
OuterClass
w=0:x=0:y=0:z=0
w=1:x=2:y=3:z=4
Outer: OuterClass
Outer: 1
Outer: 2
Outer: 3
Outer: 4
[NestedClassTest.java, OuterClass.java]
[NestedClassTest.class, OuterClass$1.class, OuterClass$1Logger.class, OuterClass$InnerClass.class, OuterClass$StaticNestedClass.class, OuterClass.class]
Observa que cuando se compila OuterClass, se crean archivos de clase separados para la clase interna, clase interna local y clase anidada estática.
Beneficios de las clases internas en Java
- Si una clase es útil solo para una clase, tiene sentido mantenerla anidada y junta. Esto ayuda en el empaquetado de las clases.
- Las clases internas de Java implementan la encapsulación. Tenga en cuenta que las clases internas pueden acceder a los miembros privados de la clase externa y al mismo tiempo podemos ocultar la clase interna del mundo exterior.
- Mantener la clase pequeña dentro de las clases de nivel superior coloca el código más cerca de donde se utiliza y hace que el código sea más legible y mantenible.
Eso es todo para la clase interna de Java.
Source:
https://www.digitalocean.com/community/tutorials/java-inner-class