Java-grænseflader forklaret med eksempler

Grænseflader

Interface i Java er lidt ligesom klassen, men med en betydelig forskel: en interfacekan kun have metodesignaturer, felter og standardmetoder. Siden Java 8 kan du også oprette standardmetoder. I den næste blok kan du se et eksempel på interface:

public interface Vehicle { public String licensePlate = ""; public float maxVel public void start(); public void stop(); default void blowHorn(){ System.out.println("Blowing horn"); } }

Grænsefladen ovenfor indeholder to felter, to metoder og en standardmetode. Alene er det ikke til stor nytte, men de bruges normalt sammen med klasser. Hvordan? Enkelt, du skal sørge for, at det klasses implements.

public class Car implements Vehicle { public void start() { System.out.println("starting engine..."); } public void stop() { System.out.println("stopping engine..."); } }

Nu er der en grundregel : Klassen skal implementere alle metoderne i grænsefladen. Metoderne skal have nøjagtig samme signatur (navn, parametre og undtagelser) som beskrevet i grænsefladen. Klassen behøver dog ikke at erklære felterne, kun metoderne.

Forekomster af et interface

Når du opretter en Java-klasse, som en implementshvilken som helst grænseflade, kan objektforekomsten henvises til som en forekomst af grænsefladen. Dette koncept svarer til konceptet for arv instantiering.

// following our previous example Vehicle tesla = new Car(); tesla.start(); // starting engine ...

Et interface kan ikke indeholde konstruktormetoder. Derfor kan du ikke oprette en forekomst af selve et interface. Du skal oprette en forekomst af en klasse, der implementerer et interface for at henvise til det.

Tænk på grænseflader som en tom kontraktformular eller en skabelon.

Hvad kan du gøre med denne funktion? Polymorfisme! Du kan kun bruge grænseflader til at henvise til objektforekomster!

class Truck implements Vehicle { public void start() { System.out.println("starting truck engine..."); } public void stop() { System.out.println("stopping truck engine..."); } } class Starter { // static method, can be called without instantiating the class public static void startEngine(Vehicle vehicle) { vehicle.start(); } } Vehicle tesla = new Car(); Vehicle tata = new Truck(); Starter.startEngine(tesla); // starting engine ... Starter.startEngine(tata); // starting truck engine ...

Men hvad med flere grænseflader?

Ja, du kan implementere flere grænseflader i en enkelt klasse. Mens du i arv inden for klasser var begrænset til kun at arve en klasse, kan du her udvide et hvilket som helst antal grænseflader. Men glem ikke at implementere alle metoderne til alle grænsefladerne, ellers mislykkes kompilering!

public interface GPS { public void getCoordinates(); } public interface Radio { public void startRadio(); public void stopRadio(); } public class Smartphone implements GPS,Radio { public void getCoordinates() { // return some coordinates } public void startRadio() { // start Radio } public void stopRadio() { // stop Radio } }

Nogle funktioner i grænseflader

  • Du kan placere variabler i et interface, selvom det ikke vil være en fornuftig beslutning, da klasser ikke er bundet til at have den samme variabel. Kort sagt, undgå at placere variabler!
  • Alle variabler og metoder i et interface er offentlige, selvom du udelader publicnøgleordet.
  • Et interface kan ikke specificere implementeringen af ​​en bestemt metode. Det er op til klasserne at gøre det. Selvom der har været en nylig undtagelse (se nedenfor).
  • Hvis en klasse implementerer flere grænseflader, er der en fjern chance for overlapning af metodesignatur. Da Java ikke tillader flere metoder med nøjagtig samme signatur, kan dette føre til problemer. Se dette spørgsmål for mere info.

Interface standardmetoder

Før Java 8 havde vi ingen måde at dirigere et interface til at have en bestemt metodeimplementering. Dette fører til meget forvirring og kodebrydninger, hvis en interface-definition pludselig ændres.

Antag, du skrev et open source-bibliotek, der indeholder et interface. Sig, dine kunder, dvs. næsten alle udviklere rundt om i verden, bruger det tungt og er glade. Nu har du været nødt til at opgradere biblioteket ved at tilføje en ny metodedefinition til grænsefladen for at understøtte en ny funktion. Men det ville bryde alle builds, da alle klasser, der implementerer det interface, skal ændres nu. Hvilken katastrofe!

Heldigvis giver Java 8 os nu defaultmetoder til grænseflader. En defaultmetode kan indeholde sin egen implementering direkte i grænsefladen! Så hvis en klasse ikke implementerer en standardmetode, tager compileren den implementering, der er nævnt i grænsefladen. Dejligt, ikke? Så i dit bibliotek kan du tilføje et hvilket som helst antal standardmetoder i grænseflader uden frygt for at bryde noget!

public interface GPS { public void getCoordinates(); default public void getRoughCoordinates() { // implementation to return coordinates from rough sources // such as wifi & mobile System.out.println("Fetching rough coordinates..."); } } public interface Radio { public void startRadio(); public void stopRadio(); } public class Smartphone implements GPS,Radio { public void getCoordinates() { // return some coordinates } public void startRadio() { // start Radio } public void stopRadio() { // stop Radio } // no implementation of getRoughCoordinates() } Smartphone motoG = new Smartphone(); motog.getRoughCoordinates(); // Fetching rough coordinates...

Men hvad sker der, hvis to grænseflader har samme metodesignatur?

Fantastisk spørgsmål. I så fald, hvis du ikke leverer implementeringen i klassen, bliver dårlig compiler forvirret og simpelthen mislykkes! Du skal også angive en standardmetodeimplementering inden for klassen. Der er også en smidig måde at bruge supertil at kalde hvilken implementering du kan lide:

public interface Radio { // public void startRadio(); // public void stopRadio(); default public void next() { System.out.println("Next from Radio"); } } public interface MusicPlayer { // public void start(); // public void pause(); // public void stop(); default public void next() { System.out.println("Next from MusicPlayer"); } } public class Smartphone implements Radio, MusicPlayer { public void next() { // Suppose you want to call MusicPlayer next MusicPlayer.super.next(); } } Smartphone motoG = new Smartphone(); motoG.next(); // Next from MusicPlayer

Static Methods in Interfaces

Also new to Java 8 is the ability to add static methods to interfaces. Static methods in interfaces are almost identical to static methods in concrete classes. The only big difference is that static methods are not inherited in the classes that implement the interface. This means that the interface is referenced when calling the static method not the class that implements it.

interface MusicPlayer { public static void commercial(String sponsor) { System.out.println("Now for a message brought to you by " + sponsor); } public void play(); } class Smartphone implements MusicPlayer { public void play() { System.out.println("Playing from smartphone"); } } class Main { public static void main(String[] args) { Smartphone motoG = new Smartphone(); MusicPlayer.commercial("Motorola"); // Called on interface not on implementing class // motoG.commercial("Motorola"); // This would cause a compilation error } }

Inheriting an Interface

It is also possible in Java for an Interface to inherit another Interface, by using, you guessed it, extends keyword:

public interface Player { public void start(); public void pause(); public void stop(); } public interface MusicPlayer extends Player { default public void next() { System.out.println("Next from MusicPlayer"); } }

That means, the Class implementing MusicPlayer Interface has to implement all methods of MusicPlayer as well as Player:

public class SmartPhone implements MusicPlayer { public void start() { System.out.println("start"); } public void stop() { System.out.println("stop"); } public void pause() { System.out.println("pause"); } }

Så nu har du et godt kendskab til Java-grænseflader! Gå og lær om abstrakte klasser for at se, hvordan Java giver dig endnu en måde at definere kontrakter på.