Anonyme klasser i Java

1. Introduktion

I denne vejledning overvejer vi anonyme klasser i Java.

Vi beskriver, hvordan vi kan erklære og oprette forekomster af dem. Vi diskuterer også kort deres egenskaber og begrænsninger.

2. Anonym klassedeklaration

Anonyme klasser er indre klasser uden navn. Da de ikke har noget navn, kan vi ikke bruge dem til at oprette forekomster af anonyme klasser. Som et resultat er vi nødt til at erklære og instantere anonyme klasser i et enkelt udtryk på anvendelsesstedet.

Vi kan enten udvide en eksisterende klasse eller implementere en grænseflade.

2.1. Forlæng en klasse

Når vi instantierer en anonym klasse fra en eksisterende, bruger vi følgende syntaks:

I parentes specificerer vi de parametre, der kræves af konstruktøren af ​​den klasse, som vi udvider:

ny bog ("Designmønstre") {@ Override public String description () {return "Famous GoF book."; }}

Hvis forældreklassekonstruktøren ikke accepterer nogen argumenter, skal vi naturligvis lade parenteserne være tomme.

2.2. Implementere en grænseflade

Vi kan også instantiere en anonym klasse fra en grænseflade:

Det er klart, at Java's grænseflader ikke har konstruktører, så parenteserne forbliver altid tomme. Dette er den eneste måde, vi skal gøre det for at implementere grænseflades metoder:

ny Runnable () {@Override public void run () {...}}

Når vi har instantificeret en anonym klasse, kan vi tildele denne forekomst til en variabel for at kunne henvise til den et eller andet sted senere.

Vi kan gøre dette ved hjælp af standardsyntaxen for Java-udtryk:

Runnable action = new Runnable () {@Override public void run () {...}};

Som vi allerede nævnte, en anonym klassedeklaration er et udtryk, derfor skal den være en del af en erklæring. Dette forklarer, hvorfor vi har sat et semikolon i slutningen af ​​udsagnet.

Det er klart, at vi kan undgå at tildele forekomsten til en variabel, hvis vi opretter den forekomst inline:

Listehandlinger = ny ArrayList (); actions.add (ny Runnable () {@Override public void run () {...}});

Vi bør bruge denne syntaks med stor omhu, da det let kan lide kodelæsbarheden, især når implementeringen af løb() metode tager meget plads.

3. Anonyme klasseegenskaber

Der er visse særlige forhold ved brug af anonyme klasser med hensyn til sædvanlige topklasser. Her berører vi kort de mest praktiske spørgsmål. For at få den mest præcise og opdaterede information kan vi altid se på Java Language Specification.

3.1. Konstruktør

Syntaksen for anonyme klasser tillader os ikke at få dem til at implementere flere grænseflader. Under byggeriet, der findes muligvis nøjagtigt en forekomst af en anonym klasse. Derfor kan de aldrig være abstrakte. Da de ikke har noget navn, kan vi ikke udvide dem. Af samme grund kan anonyme klasser ikke udtrykkeligt have erklæret konstruktører.

Faktisk er fraværet af en konstruktør ikke noget problem for os af følgende grunde:

  1. vi opretter anonyme klasseinstanser i samme øjeblik som vi erklærer dem
  2. fra anonyme klasseinstanser kan vi få adgang til lokale variabler og omslutte klassens medlemmer

3.2. Statiske medlemmer

Anonyme klasser kan ikke have nogen statiske medlemmer undtagen dem, der er konstante.

For eksempel kompilerer dette ikke:

ny Runnable () {statisk endelig int x = 0; statisk int y = 0; // kompileringsfejl! @Override public void run () {...}};

I stedet får vi følgende fejl:

Feltet y kan ikke erklæres statisk i en ikke-statisk indre type, medmindre det initialiseres med et konstant udtryk

3.3. Variabler

Anonyme klasser fanger lokale variabler, der er inden for rækkevidden af ​​den blok, hvor vi har erklæret klassen:

int-antal = 1; Runnable action = new Runnable () {@Override public void run () {System.out.println ("Kan køres med fangede variabler:" + count); }}; 

Som vi ser, de lokale variabler tælle og handling er defineret i samme blok. Af denne grund kan vi få adgang tælle indefra klassedeklarationen.

Bemærk at for at være i stand til at bruge lokale variabler skal de være endelige. Siden JDK 8 er det ikke længere nødvendigt, at vi erklærer variabler med nøgleordet endelig. Ikke desto mindre skal disse variabler være endelig. Ellers får vi en kompileringsfejl:

[FEJL] lokale variabler, der henvises til fra en indre klasse, skal være endelige eller effektivt endelige

For at kompilatoren beslutter, at en variabel faktisk er uforanderlig i koden, skal der kun være et sted, hvor vi tildeler en værdi til den. Vi finder muligvis mere information om effektive endelige variabler i vores artikel "Hvorfor skal lokale variabler, der bruges i Lambdas, være endelige eller effektive endelige?"

Lad os bare nævne, at som enhver indre klasse, en anonym klasse kan få adgang til alle medlemmer af sin klasse.

4. Anonyme klassesager

Der kan være et stort udvalg af applikationer af anonyme klasser. Lad os undersøge nogle mulige brugssager.

4.1. Klassehierarki og indkapsling

Vi bør bruge indre klasser i almindelige brugssager og anonyme i meget specifikke for at opnå et renere hierarki af klasser i vores applikation. Når vi bruger indre klasser, opnår vi muligvis en finere indkapsling af den indesluttende klasses data. Hvis vi definerer den indre klassefunktionalitet i en klasse på øverste niveau, skal den vedlagte klasse have offentlig eller pakke nogle af dets medlemmers synlighed. Naturligvis er der situationer, hvor det ikke er meget værdsat eller endda accepteret.

4.2. Renere projektstruktur

Vi bruger normalt anonyme klasser, når vi skal ændre i farten implementeringen af ​​metoder i nogle klasser. I dette tilfælde kan vi undgå at tilføje nye * .java filer til projektet for at definere klasser på øverste niveau. Dette gælder især, hvis den øverste klasse kun bruges én gang.

4.3. UI-begivenhedslyttere

I applikationer med en grafisk grænseflade er den mest almindelige anvendelse af anonyme klasser at skabe forskellige begivenhedslyttere. For eksempel i følgende uddrag:

button.addActionListener (ny ActionListener () {offentlig ugyldig handling Udført (ActionEvent e) {...}}

vi opretter en forekomst af en anonym klasse, der implementerer interface ActionListener. Dens handling udført metode udløses, når en bruger klikker på knappen.

Siden Java 8 synes lambda-udtryk dog at være en mere foretrukken måde.

5. Generelt billede

Anonyme klasser, som vi overvejede ovenfor, er kun et bestemt tilfælde af indlejrede klasser. Generelt, en indlejret klasse er en klasse, der er erklæret inde i en anden klasse eller grænseflade:

Ser vi på diagrammet, ser vi, at anonyme klasser sammen med lokal og ikke-statiske medlemmer danne den såkaldte indre klasser. Sammen med statisk medlem klasser, de danner de indlejrede klasser.

6. Konklusion

I denne artikel har vi overvejet forskellige aspekter af anonyme Java-klasser. Vi har også beskrevet et generelt hierarki af indlejrede klasser.

Som altid er den komplette kode tilgængelig i vores GitHub-lager.


$config[zx-auto] not found$config[zx-overlay] not found