Interfețe

Interfața în Java seamănă puțin cu clasa, dar cu o diferență semnificativă: an interface poate sa numai au semnături de metode, câmpuri și metode implicite. De la Java 8, puteți crea și metode implicite. În blocul următor puteți vedea un exemplu de interfață:

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

Interfața de mai sus conține două câmpuri, două metode și o metodă implicită. Singur, nu este de mare folos, dar de obicei sunt folosite împreună cu clasele. Cum? Simplu, trebuie să vă asigurați că aveți o clasă implements aceasta.

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

Acum, există un regula de baza: Clasa trebuie să implementeze toate a metodelor din interfață. Metodele trebuie să aibă exact la fel semnătură (nume, parametri și excepții) așa cum este descris în interfață. Clasa nu trebuie să declare câmpurile, însă, doar metodele.

Instanțe ale unei interfețe

Odată ce creați o clasă Java care implements orice interfață, instanța obiect poate fi referită ca instanță a interfeței. Acest concept este similar cu cel al instanțierii prin moștenire.

// following our previous example

Vehicle tesla = new Car();

tesla.start(); // starting engine ...

O interfață nu poti conține un constructor metode. Prin urmare, tu nu poti creați o instanță a unei interfețe în sine. Trebuie să creați o instanță a unei clase care implementează o interfață pentru a o referi.

Gândiți-vă la interfețe ca la un formular de contract necompletat sau ca un șablon.

Ce puteți face cu această caracteristică? Polimorfism! Puteți utiliza numai interfețe pentru a vă referi la instanțe de obiect!

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

Dar ce zici de mai multe interfețe?

Da, puteți implementa mai multe interfețe într-o singură clasă. In timp ce in Moştenire în cadrul claselor vi s-a restricționat să moșteniți o singură clasă, aici puteți extinde orice număr de interfețe. Dar nu uitați să implementați toate a metodelor tuturor interfețelor, altfel compilarea va eșua!

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

Unele caracteristici ale interfețelor

  • Puteți plasa variabile într-o interfață, deși nu va fi o decizie sensibilă, deoarece clasele nu sunt obligate să aibă aceeași variabilă. Pe scurt, evitați plasarea variabilelor!
  • Toate variabilele și metodele dintr-o interfață sunt publice, chiar dacă nu lăsați public cuvânt cheie.
  • O interfață nu poate specifica implementarea unei anumite metode. Depinde de clasă să o facă. Deși a existat o excepție recentă (a se vedea mai jos).
  • Dacă o clasă implementează mai multe interfețe, atunci există o șansă la distanță de suprapunere a semnăturii metodei. Deoarece Java nu permite mai multe metode cu aceeași semnătură exactă, acest lucru poate duce la probleme. Vedea această întrebare pentru mai multe informatii.

Metode implicite de interfață

Înainte de Java 8, nu aveam nicio modalitate de a direcționa o interfață pentru a avea o anumită metodă de implementare. Acest lucru duce la o mulțime de confuzie și pauze de cod dacă o definiție a interfeței este modificată brusc.

Să presupunem că ați scris o bibliotecă open source, care conține o interfață. Spuneți că clienții dvs., adică practic toți dezvoltatorii din întreaga lume, îl folosesc foarte mult și sunt fericiți. Acum a trebuit să actualizați biblioteca adăugând o nouă definiție a metodei la interfață pentru a accepta o nouă caracteristică. Dar asta s-ar rupe toate construiește, deoarece toate clasele care implementează această interfață trebuie să se schimbe acum. Ce catastrofă!

Din fericire, Java 8 ne oferă acum default metode pentru interfețe. A default metodă poate sa conține propria implementare direct în cadrul interfeței! Deci, dacă o clasă nu implementează o metodă implicită, compilatorul va lua implementarea menționată în interfață. Frumos, nu-i așa? Deci, în biblioteca dvs., puteți adăuga orice număr de metode implicite în interfețe fără teama de a sparge ceva!

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

Dar, ce se întâmplă dacă două interfețe au aceeași metodă de semnătură?

Întrebare minunată. În acest caz, dacă nu furnizați implementarea în clasă, compilatorul slab va fi confuz și va eșua pur și simplu! Trebuie să furnizați și o implementare implicită a metodei în cadrul clasei. Există, de asemenea, un mod inteligent de utilizare super pentru a apela ce implementare vă place:

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

Metode statice în interfețe

De asemenea, noua versiune Java 8 este capacitatea de a adăuga metode statice la interfețe. Metodele statice din interfețe sunt aproape identice cu metodele statice din clasele concrete. Singura diferență mare este că static metodele nu sunt moștenite în clasele care implementează interfața. Aceasta înseamnă că se face referință la interfață atunci când se apelează metoda statică nu la clasa care o implementează.

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

Moștenirea unei interfețe

De asemenea, în Java este posibilă o interfață pentru moşteni o altă interfață, folosind, ai ghicit, extends cuvânt cheie:

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

Asta înseamnă, implementarea clasei MusicPlayer Interfața trebuie să fie implementată toate metode de MusicPlayer precum și 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");
    }
}

Deci, acum aveți o bună înțelegere a interfețelor Java! Învață despre clasele abstracte pentru a vedea cum Java îți oferă încă un alt mod de a defini contracte.