La classe interna di Java è definita all’interno del corpo di un’altra classe. La classe interna di Java può essere dichiarata private, public, protected o con accesso di default, mentre una classe esterna può avere solo accesso public o di default. Le classi annidate di Java sono divise in due tipi.
-
classe annidata statica
Se la classe annidata è statica, allora viene chiamata classe annidata statica. Le classi annidate statiche possono accedere solo ai membri statici della classe esterna. Una classe annidata statica è la stessa di qualsiasi altra classe di primo livello e viene annidata solo per comodità di impacchettamento. Un oggetto di classe statica può essere creato con la seguente istruzione.
OuterClass.StaticNestedClass nestedObject = new OuterClass.StaticNestedClass();
-
Classe interna di Java
Qualsiasi classe nidificata non statica è nota come classe interna in Java. La classe interna di Java è associata all’oggetto della classe e può accedere a tutte le variabili e i metodi della classe esterna. Poiché le classi interne sono associate all’istanza, non possiamo avere variabili statiche al loro interno. L’oggetto della classe interna di Java fa parte dell’oggetto della classe esterna e per creare un’istanza della classe interna, prima dobbiamo creare un’istanza della classe esterna. La classe interna di Java può essere istanziata in questo modo;
OuterClass outerObject = new OuterClass(); OuterClass.InnerClass innerObject = outerObject.new InnerClass();
Ci sono due tipi speciali di classi interne Java.
-
classe interna locale
Se una classe è definita all’interno di un corpo di un metodo, è nota come classe interna locale. Poiché la classe interna locale non è associata all’oggetto, non possiamo utilizzare i modificatori di accesso privato, pubblico o protetto con essa. Gli unici modificatori consentiti sono astratto o finale. Una classe interna locale può accedere a tutti i membri della classe esterna e alle variabili locali finali nello scope in cui è definita. Inoltre, può anche accedere a una variabile locale non finale del metodo in cui è definita, ma non può modificarla. Quindi, se si tenta di stampare il valore di una variabile locale non finale, sarà consentito, ma se si tenta di cambiarne il valore dall’interno del metodo della classe interna locale, si otterrà un errore in fase di compilazione. Una classe interna locale può essere definita come segue:
package com.journaldev.innerclasses; public class MainClass { private String s_main_class; public void print() { String s_print_method = ""; // classe interna locale all'interno del metodo class Logger { // in grado di accedere alle variabili della classe esterna String name = s_main_class; // in grado di accedere alle variabili del metodo non finali String name1 = s_print_method; public void foo() { String name1 = s_print_method; // Il codice seguente genererà un errore in fase di compilazione: // La variabile locale s_print_method definita in uno scope esterno deve essere finale o effettivamente finale // s_print_method= ":"; } } // istanziare la classe interna locale nel metodo per utilizzarla Logger logger = new Logger(); } }
Possiamo definire una classe interna locale all’interno di qualsiasi blocco, come un blocco statico, un blocco if-else, ecc. Tuttavia, in questo caso, lo scope della classe sarà molto limitato.
public class MainClass { static { class Foo { } Foo f = new Foo(); } public void bar() { if(1 < 2) { class Test { } Test t1 = new Test(); } // Il seguente codice genererà un errore a causa dello scope della classe //Test t = new Test(); //Foo f = new Foo(); } }
-
classe interna anonima
Una classe interna anonima senza nome è conosciuta come classe interna anonima. Una classe anonima viene definita e istanziata in un’unica istruzione. La classe interna anonima estende sempre una classe o implementa un’interfaccia. Poiché una classe anonima non ha un nome, non è possibile definire un costruttore per una classe anonima. Le classi interne anonime sono accessibili solo nel punto in cui sono definite. È un po’ difficile definire come creare una classe interna anonima, vedremo l’utilizzo in tempo reale nel programma di test qui sotto.
Ecco una classe Java che mostra come definire una classe interna Java, una classe interna statica, una classe interna locale e una classe interna anonima. 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;
//Costruttore di 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;
}
//Classe annidata statica, può accedere alle variabili/metodi statici di 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;
}
}
//Classe interna, non statica e può accedere a tutte le variabili/metodi della classe esterna
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;
}
}
//Classe interna locale
public void print(String initial) {
//Classe interna locale
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);
}
//Classe interna anonima
public String[] getFilesInDir(String dir, final String ext) {
File file = new File(dir);
//Classe interna anonima
implementing FilenameFilter interface
String[] filesList = file.list(new FilenameFilter() {
@Override
public boolean accept(File dir, String name) {
return name.endsWith(ext);
}
});
return filesList;
}
}
Ecco il programma di test che mostra come istanziare e utilizzare la classe interna in Java. InnerClassTest.java
package com.journaldev.nested;
import java.util.Arrays;
//Le classi annidate possono essere utilizzate nell'import per una facile istanziazione
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);
//Esempio di classe annidata statica
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);
//Esempio di classe interna
InnerClass innerClass = outer.new InnerClass();
System.out.println(innerClass.getName());
System.out.println(innerClass);
innerClass.setValues();
System.out.println(innerClass);
//Chiamata del metodo utilizzando la classe interna locale
outer.print("Outer");
//Chiamata del metodo utilizzando la classe interna anonima
System.out.println(Arrays.toString(outer.getFilesInDir("src/com/journaldev/nested", ".java")));
System.out.println(Arrays.toString(outer.getFilesInDir("bin/com/journaldev/nested", ".class")));
}
}
Ecco l’output del programma di esempio di classe interna Java sopra.
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]
Si noti che quando OuterClass viene compilata, vengono creati file di classe separati per la classe interna, la classe interna locale e la classe annidata statica.
Vantaggi della classe interna Java
- Se una classe è utile solo a una classe, ha senso tenerla annidata e insieme. Aiuta nell’organizzazione delle classi.
- Le classi interne di Java implementano l’incapsulamento. Nota che le classi interne possono accedere ai membri privati della classe esterna e allo stesso tempo possiamo nascondere la classe interna dal mondo esterno.
- Mantenere la classe piccola all’interno delle classi di primo livello posiziona il codice più vicino a dove viene utilizzato e rende il codice più leggibile e manutenibile.
Questo è tutto per la classe interna di Java.
Source:
https://www.digitalocean.com/community/tutorials/java-inner-class