Οι διεπαφές Java εξηγούνται με παραδείγματα

Διεπαφές

Η διεπαφή στην Java μοιάζει λίγο με την κλάση, αλλά με σημαντική διαφορά: interfaceμπορεί να έχει μόνο υπογραφές μεθόδων, πεδία και προεπιλεγμένες μεθόδους. Από το Java 8, μπορείτε επίσης να δημιουργήσετε προεπιλεγμένες μεθόδους. Στο επόμενο μπλοκ μπορείτε να δείτε ένα παράδειγμα διεπαφής:

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

Η παραπάνω διεπαφή περιέχει δύο πεδία, δύο μεθόδους και μια προεπιλεγμένη μέθοδο. Μόνο, δεν έχει μεγάλη χρησιμότητα, αλλά συνήθως χρησιμοποιείται μαζί με τις τάξεις. Πως? Απλό, πρέπει να βεβαιωθείτε ότι κάποια κατηγορία implements.

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

Τώρα, υπάρχει ένας βασικός κανόνας : Η κλάση πρέπει να εφαρμόσει όλες τις μεθόδους στη διεπαφή. Οι μέθοδοι πρέπει να έχουν την ίδια ακριβώς υπογραφή (όνομα, παράμετροι και εξαιρέσεις) όπως περιγράφεται στη διεπαφή. Η τάξη δεν χρειάζεται να δηλώσει τα πεδία, ωστόσο, μόνο τις μεθόδους.

Περιπτώσεις διασύνδεσης

Μόλις δημιουργήσετε μια κλάση Java που implementsοποιαδήποτε διασύνδεση, η παρουσία αντικειμένου μπορεί να αναφέρεται ως παρουσία της διεπαφής. Αυτή η έννοια είναι παρόμοια με αυτήν της κληρονομικής περίπτωσης.

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

Μια διεπαφή δεν μπορεί να περιέχει μεθόδους κατασκευαστή. Επομένως, δεν μπορείτε να δημιουργήσετε μια παρουσία μιας ίδιας διεπαφής. Πρέπει να δημιουργήσετε μια παρουσία κάποιας κλάσης που εφαρμόζει μια διεπαφή για να την αναφέρετε.

Σκεφτείτε τις διεπαφές ως κενή φόρμα σύμβασης ή πρότυπο.

Τι μπορείτε να κάνετε με αυτήν τη δυνατότητα; Πολυμορφισμός! Μπορείτε να χρησιμοποιήσετε μόνο διεπαφές για αναφορά σε παρουσίες αντικειμένων!

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 ...

Τι γίνεται όμως με πολλαπλές διεπαφές;

Ναι, μπορείτε να εφαρμόσετε πολλές διεπαφές σε μία κλάση. Ενώ βρίσκεστε στην κληρονομικότητα εντός τάξεων, περιορίσατε να κληρονομήσετε μόνο μία τάξη, εδώ μπορείτε να επεκτείνετε οποιονδήποτε αριθμό διεπαφών. Αλλά μην ξεχάσετε να εφαρμόσετε όλες τις μεθόδους όλων των διεπαφών, διαφορετικά η συλλογή θα αποτύχει!

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 } }

Ορισμένες δυνατότητες του Interfaces

  • Μπορείτε να τοποθετήσετε μεταβλητές σε μια διεπαφή, αν και δεν θα είναι λογική απόφαση, καθώς οι τάξεις δεν είναι υποχρεωμένες να έχουν την ίδια μεταβλητή. Εν ολίγοις, αποφύγετε την τοποθέτηση μεταβλητών!
  • Όλες οι μεταβλητές και οι μέθοδοι σε μια διεπαφή είναι δημόσιες, ακόμη και αν αφήσετε τη publicλέξη-κλειδί.
  • Μια διεπαφή δεν μπορεί να καθορίσει την εφαρμογή μιας συγκεκριμένης μεθόδου. Εναπόκειται στις τάξεις να το κάνουν. Παρόλο που υπήρξε πρόσφατη εξαίρεση (βλ. Παρακάτω).
  • Εάν μια κλάση εφαρμόζει πολλαπλές διεπαφές, τότε υπάρχει μια απομακρυσμένη πιθανότητα επικάλυψης υπογραφής μεθόδου. Δεδομένου ότι η Java δεν επιτρέπει πολλαπλές μεθόδους με την ίδια ακριβώς υπογραφή, αυτό μπορεί να οδηγήσει σε προβλήματα. Δείτε αυτήν την ερώτηση για περισσότερες πληροφορίες.

Προεπιλεγμένες μέθοδοι διεπαφής

Πριν από την Java 8, δεν είχαμε κανέναν τρόπο να κατευθύνουμε μια διεπαφή για να έχουμε μια συγκεκριμένη εφαρμογή μεθόδου. Αυτό οδηγεί σε μεγάλη σύγχυση και διαρροή κώδικα εάν αλλάξει ξαφνικά ένας ορισμός διασύνδεσης.

Ας υποθέσουμε, γράψατε μια βιβλιοθήκη ανοιχτού κώδικα, η οποία περιέχει μια διεπαφή. Ας πούμε, οι πελάτες σας, δηλαδή σχεδόν όλοι οι προγραμματιστές σε όλο τον κόσμο, το χρησιμοποιούν πολύ και είναι ευχαριστημένοι. Τώρα πρέπει να αναβαθμίσετε τη βιβλιοθήκη προσθέτοντας έναν νέο ορισμό μεθόδου στη διεπαφή για να υποστηρίξετε μια νέα δυνατότητα. Αλλά αυτό θα σπάσει όλες τις εκδόσεις αφού όλες οι κλάσεις που εφαρμόζουν αυτή τη διεπαφή πρέπει να αλλάξουν τώρα. Τι καταστροφή!

Ευτυχώς, το Java 8 μας παρέχει τώρα defaultμεθόδους για διασυνδέσεις. Μια defaultμέθοδος μπορεί να περιέχει τη δική της εφαρμογή απευθείας στη διεπαφή! Έτσι, εάν μια κλάση δεν εφαρμόζει μια προεπιλεγμένη μέθοδο, ο μεταγλωττιστής θα λάβει την υλοποίηση που αναφέρεται στη διεπαφή. Ωραία, έτσι δεν είναι; Έτσι, στη βιβλιοθήκη σας, μπορείτε να προσθέσετε οποιονδήποτε αριθμό προεπιλεγμένων μεθόδων σε διεπαφές χωρίς τον φόβο να σπάσετε τίποτα!

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...

Αλλά, τι θα συμβεί αν δύο διεπαφές έχουν την ίδια υπογραφή μεθόδου;

Φοβερή ερώτηση. Σε αυτήν την περίπτωση, εάν δεν παρέχετε την εφαρμογή στην τάξη, ο κακός μεταγλωττιστής θα μπερδευτεί και θα αποτύχει! Πρέπει επίσης να παρέχετε μια προεπιλεγμένη εφαρμογή μεθόδου μέσα στην τάξη επίσης. Υπάρχει επίσης ένας καλός τρόπος superγια να καλέσετε ποια εφαρμογή θέλετε:

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

Στατικές μέθοδοι στις διεπαφές

Επίσης νέο στο Java 8 είναι η δυνατότητα προσθήκης στατικών μεθόδων στις διεπαφές. Οι στατικές μέθοδοι στις διεπαφές είναι σχεδόν ταυτόσημες με τις στατικές μεθόδους σε συγκεκριμένες κατηγορίες. Η μόνη μεγάλη διαφορά είναι ότι οι staticμέθοδοι δεν κληρονομούνται στις τάξεις που εφαρμόζουν τη διεπαφή. Αυτό σημαίνει ότι η διεπαφή αναφέρεται όταν καλείτε τη στατική μέθοδο και όχι την κλάση που την εφαρμόζει.

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 } }

Κληρονομιά μιας διασύνδεσης

Είναι επίσης δυνατό στην Java να κληρονομήσει μια άλλη διεπαφή, χρησιμοποιώντας, μαντέψατε, extendsλέξη-κλειδί:

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"); } }

Αυτό σημαίνει ότι, η MusicPlayerδιεπαφή εφαρμογής κλάσης πρέπει να εφαρμόζει όλες τις μεθόδους, MusicPlayerκαθώς και 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"); } }

Τώρα λοιπόν έχετε καλή κατανόηση των διεπαφών Java! Πηγαίνετε να μάθετε για τα Abstract Classes για να δείτε πώς η Java σάς δίνει έναν ακόμη τρόπο να καθορίσετε συμβόλαια.