Statiske og standardmetoder i grænseflader i Java

1. Oversigt

Java 8 bragte et par helt nye funktioner til bordet, herunder lambda-udtryk, funktionelle grænseflader, metodereferencer, streams, valgfri og statisk og Standard metoder i grænseflader.

Nogle af dem er allerede dækket af denne artikel. Ikke desto mindre, statisk og Standard metoder i grænseflader fortjener et dybere blik alene.

I denne artikel vil vi diskutere i dybden hvordan man bruger statisk og Standard metoder i grænseflader og gennemgå nogle brugssager, hvor de kan være nyttige.

2. Hvorfor der er brug for standardmetoder i grænseflader

Ligesom almindelige grænseflademetoder, standardmetoder er implicit offentlige - der er ingen grund til at specificere offentlig modifikator.

I modsætning til almindelige grænseflademetoder er de det erklæret med Standard nøgleord i begyndelsen af ​​metodesignaturen, og de give en implementering.

Lad os se et simpelt eksempel:

offentlig grænseflade MyInterface {// almindelige grænseflademetoder standard ugyldig defaultMethod () {// standardmetodeimplementering}}

Grunden til Standard metoder blev inkluderet i Java 8-udgivelsen er ret indlysende.

I et typisk design baseret på abstraktioner, hvor en grænseflade har en eller flere implementeringer, hvis en eller flere metoder føjes til grænsefladen, vil alle implementeringer også blive tvunget til at implementere dem. Ellers brydes designet bare sammen.

Standardgrænseflademetoder er en effektiv måde at håndtere dette problem på. De tillad os at tilføje nye metoder til en grænseflade, der automatisk er tilgængelige i implementeringerne. Der er således ikke behov for at ændre implementeringsklasser.

På denne måde bagudkompatibilitet er pænt bevaret uden at skulle omlægge implementerne.

3. Standardgrænseflademetoder i aktion

For bedre at forstå funktionaliteten af Standard interface-metoder, lad os oprette et simpelt eksempel.

Sig, at vi har en naiv Køretøj interface og kun en implementering. Der kunne være mere, men lad os holde det så simpelt:

offentlig grænseflade Vehicle {String getBrand (); String speedUp (); String slowDown (); standard String turnAlarmOn () {return "Tænder køretøjets alarm."; } standard String turnAlarmOff () {return "Slå køretøjets alarm fra."; }}

Og lad os skrive implementeringsklassen:

offentlig klasse bilværktøjer køretøj {private String brand; // constructors / getters @Override public String getBrand () {return brand; } @ Override public String speedUp () {return "Bilen er i fart."; } @ Override public String slowDown () {return "Bilen bremser."; }} 

Endelig, lad os definere en typisk vigtigste klasse, som skaber en forekomst af Bil og kalder dens metoder:

public static void main (String [] args) {Vehicle car = new Car ("BMW"); System.out.println (car.getBrand ()); System.out.println (bil.speedUp ()); System.out.println (bil.slowDown ()); System.out.println (car.turnAlarmOn ()); System.out.println (car.turnAlarmOff ()); }

Bemærk hvordan Standard metoder turnAlarmOn () og turnAlarmOff () fra vores Køretøj interface er automatisk tilgængelig i Bil klasse.

Desuden, hvis vi på et eller andet tidspunkt beslutter at tilføje flere Standard metoder til Køretøj interface, vil applikationen stadig fortsætte med at arbejde, og vi behøver ikke tvinge klassen til at levere implementeringer til de nye metoder.

Den mest typiske brug af standardmetoder i grænseflader er til trinvis at give yderligere funktionalitet til en given type uden at nedbryde implementeringsklasser.

Derudover kan de bruges til give yderligere funktionalitet omkring en eksisterende abstrakt metode:

offentlig grænseflade Køretøj {// yderligere grænseflademetoder dobbelt getSpeed ​​(); standard dobbelt getSpeedInKMH (dobbelt hastighed) {// konvertering}}

4. Regler for arv af flere grænseflader

Standardgrænseflademetoder er faktisk en ret flot funktion, men med nogle advarsler værd at nævne. Da Java tillader klasser at implementere flere grænseflader, er det vigtigt at vide det hvad sker der, når en klasse implementerer flere grænseflader, der definerer det samme Standard metoder.

For bedre at forstå dette scenario, lad os definere et nyt Alarm grænseflade og refaktor Bil klasse:

offentlig grænseflade Alarm {standard String turnAlarmOn () {return "Tænder alarmen."; } standard String turnAlarmOff () {return "Slå alarmen fra."; }}

Med denne nye grænseflade, der definerer sit eget sæt Standard metoder, den Bil klasse ville implementere begge dele Køretøj og Alarm:

offentlig klasse bilimplementerer køretøj, alarm {// ...}

I dette tilfælde, koden kompilerer simpelthen ikke, da der er en konflikt forårsaget af flere interface-arv (aka diamantproblemet). Det Bil klasse ville arve begge sæt Standard metoder. Hvilke skal man kalde dengang?

For at løse denne tvetydighed skal vi eksplicit give en implementering af metoderne:

@Override public String turnAlarmOn () {// tilpasset implementering} @Override public String turnAlarmOff () {// tilpasset implementering}

Det kan vi også få vores klasse til at bruge Standard metoder til en af ​​grænsefladerne.

Lad os se et eksempel, der bruger Standard metoder fra Køretøj grænseflade:

@ Override public String turnAlarmOn () {return Vehicle.super.turnAlarmOn (); } @ Override public String turnAlarmOff () {return Vehicle.super.turnAlarmOff (); } 

På samme måde kan vi få klassen til at bruge Standard metoder defineret i Alarm grænseflade:

@Override public String turnAlarmOn () {return Alarm.super.turnAlarmOn (); } @ Override public String turnAlarmOff () {return Alarm.super.turnAlarmOff (); } 

Desuden er det jævnt muligt at gøre Bil klasse bruger begge sæt standardmetoder:

@Override public String turnAlarmOn () {return Vehicle.super.turnAlarmOn () + "" + Alarm.super.turnAlarmOn (); } @ Override public String turnAlarmOff () {return Vehicle.super.turnAlarmOff () + "" + Alarm.super.turnAlarmOff (); } 

5. Metoder til statisk grænseflade

Bortset fra at være i stand til at erklære Standard metoder i grænseflader, Java 8 giver os mulighed for at definere og implementere statisk metoder i grænseflader.

Siden statisk metoder hører ikke til et bestemt objekt, de er ikke en del af API'et for de klasser, der implementerer grænsefladen, og de skal være kaldes ved hjælp af grænsefladenavnet forud for metodens navn.

At forstå hvordan statisk metoder fungerer i grænseflader, lad os omformere Køretøj interface og tilføj det en statisk hjælpemetode:

offentlig grænseflade Køretøj {// regelmæssig / standardgrænseflade metoder statisk int getHorsePower (int rpm, int moment) {return (rpm * moment) / 5252; }} 

Definition af en statisk metode i en grænseflade er identisk med at definere en i en klasse. Desuden er en statisk metode kan påberåbes inden for andre statisk og Standard metoder.

Sig nu, at vi vil beregne hestekræfterne for et givet køretøjs motor. Vi kalder bare getHorsePower () metode:

Vehicle.getHorsePower (2500, 480)); 

Ideen bag statisk interface metoder er at tilvejebringe en enkel mekanisme, der giver os mulighed for at øge graden af ​​samhørighed af et design ved at sammensætte relaterede metoder på et enkelt sted uden at skulle oprette et objekt.

Rimeligt meget det samme kan gøres med abstrakte klasser. Den største forskel ligger i, at abstrakte klasser kan have konstruktører, tilstand og adfærd.

Desuden gør statiske metoder i grænseflader det muligt at gruppere relaterede hjælpemetoder uden at skulle oprette kunstige hjælpeklasser, der simpelthen er pladsholdere til statiske metoder.

6. Konklusion

I denne artikel undersøgte vi dybtgående brugen af statisk og Standard interface-metoder i Java 8. Ved første øjekast kan denne funktion se lidt sjusket ud, især set fra et objektorienteret puristisk perspektiv. Ideelt set bør grænseflader ikke indkapsle adfærd og bør kun bruges til at definere den offentlige API af en bestemt type.

Når det kommer til at opretholde bagudkompatibilitet med eksisterende kode, statisk og Standard metoder er en god kompromis.

Og som sædvanligt er alle kodeeksempler vist i denne artikel tilgængelige på GitHub.