Ce face Clase interne și anonime
O clasă imbricată statică (static class) este o clasă obișnuită pusă în alta ca să le grupeze; se creează cu new Exterior.Imbricata(). O clasă interioară (fără static) este legată de un obiect al clasei exterioare și îi poate citi direct câmpurile, chiar și pe cele private.
O clasă locală este declarată într-o metodă și se folosește doar acolo. O clasă anonimă se declară și se instanțiază în aceeași expresie: new Interfata() { ... }. Clasele locale și anonime pot folosi variabilele locale ale metodei, dacă acestea sunt efectiv finale.
Pentru interfețele cu o singură metodă, o lambda înlocuiește aproape mereu clasa anonimă. Clasa anonimă rămâne utilă când ai nevoie de stare proprie sau de mai multe metode. Regulă practică: preferă static class dacă nu ai nevoie de obiectul exterior.
Exemple
Exemplul 1: Clasă imbricată statică și clasă interioară
Biblioteca.Carte este statică: se creează fără bibliotecă. Imprumut este interioară: citește câmpul privat nume al bibliotecii care a creat-o.
import java.util.ArrayList;
import java.util.List;
class Biblioteca {
private final String nume;
private final List<Imprumut> imprumuturi = new ArrayList<>();
Biblioteca(String nume) {
this.nume = nume;
}
static class Carte {
final String titlu;
Carte(String titlu) { this.titlu = titlu; }
}
class Imprumut {
final Carte carte;
final String cititor;
Imprumut(Carte carte, String cititor) {
this.carte = carte;
this.cititor = cititor;
}
String fisa() {
return nume + ": „" + carte.titlu + "” împrumutată de " + cititor;
}
}
void imprumuta(Carte c, String cititor) {
imprumuturi.add(new Imprumut(c, cititor));
}
void raport() {
imprumuturi.forEach(i -> System.out.println(i.fisa()));
}
}
public class Main {
public static void main(String[] args) {
Biblioteca.Carte ion = new Biblioteca.Carte("Ion");
Biblioteca b = new Biblioteca("Biblioteca Județeană Iași");
b.imprumuta(ion, "Ana");
b.imprumuta(new Biblioteca.Carte("Baltagul"), "Radu");
b.raport();
Biblioteca.Imprumut extra = b.new Imprumut(ion, "Elena"); // sintaxa rară: obiect.new
System.out.println(extra.fisa());
}
}
Rezultat
Biblioteca Județeană Iași: „Ion” împrumutată de Ana
Biblioteca Județeană Iași: „Baltagul” împrumutată de Radu
Biblioteca Județeană Iași: „Ion” împrumutată de Elena
Exemplul 2: Clasă anonimă și lambda
Ambele comparatoare sortează după lungimea numelui. Clasa anonimă are și o stare proprie (un contor de comparații), lucru pe care o lambda nu îl poate avea.
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
public class Main {
public static void main(String[] args) {
List<String> orase = new ArrayList<>(List.of("Iași", "Constanța", "Arad", "Sibiu", "Bistrița"));
Comparator<String> anonim = new Comparator<>() {
int comparatii = 0;
@Override
public int compare(String a, String b) {
comparatii++;
return Integer.compare(a.length(), b.length());
}
@Override
public String toString() {
return "comparator cu " + comparatii + " comparații";
}
};
orase.sort(anonim);
System.out.println(orase + " | " + anonim);
orase.sort((a, b) -> Integer.compare(b.length(), a.length()));
System.out.println(orase);
}
}
Rezultat
[Iași, Arad, Sibiu, Bistrița, Constanța] | comparator cu 8 comparații
[Constanța, Bistrița, Sibiu, Iași, Arad]
Exemplul 3: Clasă locală într-o metodă
Record-ul local Rand există doar în metoda raport. Clasa locală Formatare folosește parametrul moneda al metodei, care este efectiv final.
import java.util.List;
public class Main {
static void raport(List<String> produse, List<Double> preturi, String moneda) {
record Rand(String produs, double pret) { }
class Formatare {
String linie(Rand r) {
return String.format("%-10s %8.2f %s", r.produs(), r.pret(), moneda);
}
}
Formatare f = new Formatare();
for (int i = 0; i < produse.size(); i++) {
System.out.println(f.linie(new Rand(produse.get(i), preturi.get(i))));
}
}
public static void main(String[] args) {
raport(List.of("pâine", "lapte", "cafea"), List.of(5.5, 8.9, 42.0), "lei");
}
}
Rezultat
pâine 5.50 lei
lapte 8.90 lei
cafea 42.00 lei
Greșeli frecvente
- Creezi o clasă interioară dintr-un context static fără obiect exterior:
non-static variable this cannot be referenced from a static context. Fă clasastaticsau foloseșteexterior.new Interioara(). - Modifici o variabilă locală folosită în clasa anonimă:
local variables referenced from an inner class must be final or effectively final. - Lași o clasă interioară nestatică acolo unde nu e nevoie de obiectul exterior: fiecare instanță ține o referință ascunsă spre el și îl poate ține în memorie inutil.
Comenzi înrudite
Expresii lambda: O lambda este o funcție scurtă, fără nume, scrisă ca parametri -> corp, folosită oriunde se așteaptă o interfață funcțională.static: static leagă un câmp sau o metodă de clasă, nu de un obiect: există o singură copie, accesată prin numele clasei.Clase și obiecte (class): O clasă (cuvântul cheie class) descrie un tip nou: câmpuri pentru date și metode pentru comportament; obiectele sunt instanțele ei.Interfețe (interface, implements): O interfață (interface) descrie ce metode trebuie să aibă o clasă; clasa o promite cu implements și poate implementa mai multe interfețe.record: record declară o clasă imutabilă pentru date: constructorul, accesorii, equals, hashCode și toString sunt generați automat.