Vaikka sekä extends- että implements-avainsanaa käytetään Javassa objektikeskeisen ohjelmoinnin periytymiskäsitteen toteuttamiseen, niiden välillä on hienoinen ero. Avainsanaa extends käytetään pääasiassa luokan laajentamiseen eli aliluokan luomiseen Javassa, kun taas avainsanaa implements käytetään rajapinnan toteuttamiseen Javassa. Myös rajapinta voi käyttää extends-avainsanaa toisen rajapinnan laajentamiseen. Jotta ymmärrät paremmin extends- ja implements-avainsanojen eron, sinun on myös opittava ja ymmärrettävä luokan ja rajapinnan ero Javassa.
Vaikka molemmat ovat olennainen osa sovelluskehitystä objektisuuntautuneella metodologialla, rajapinta on abstraktimpi kuin luokka, joten sitä käytetään API:n tai sopimuksen määrittelyyn.
Toisaalta luokka tarjoaa rajapinnan konkreettisen toteutuksen eli varsinaisen koodin, joka tekee tehtävän. Vaikka luokka voi olla myös abstrakti sopimuksen määrittelemiseksi, Javassa rajapinta hoitaa tämän tehtävän parhaiten. Jopa Joshua Bloch on Effective Java -kirjassaan kehottanut käyttämään rajapintoja tyypin ilmoittamiseen Javassa, koska se edistää moninkertaista periytymistä Javassa, mikä on rajoitettua verrattuna C++:aan.
Jopa Java 8:n jälkeen vain tyypin ja käyttäytymisen moninkertaista periytymistä tuetaan Javassa (ottamalla käyttöön oletusmetodit Java 8:ssa), mutta tilan moninkertaista periytymistä ei vieläkään tueta. Jos haluat lisätietoja siitä, miksi moninkertaista periytymistä ei tueta Javassa, katso täältä.
Ja jos olet uusi Java-maailmassa, suosittelen myös käymään läpi The Complete Java MasterClass -luokan Udemyssa oppiaksesi Javaa paremmin ja jäsennellymmin. Tämä on yksi parhaista ja ajan tasalla olevista kursseista, joilla voit oppia Javaa verkossa.
Mitä tarkoittaa luokan laajentaminen
Luokka voi Javassa laajentaa toista luokkaa, jolloin siitä tulee aliluokka. Kun luokka B laajentaa luokkaa A, B:stä tulee aliluokka (child) ja A:sta superclass (parent). Aliluokka voi käyttää uudelleen kaikkia vanhemman luokan ominaisuuksia, ja koodin uudelleenkäyttö on tärkeä syy luokan laajentamiseen, mutta harva ymmärtää, että tärkeämpää on määrittelysuhde, jota myöhemmin hyödynnetään polymorfismilla.
Jos esimerkiksi luokka B laajentaa luokkaa A, tyypin A viitemuuttuja voi pitää sisällään B:n objektin, mikä tarkoittaa, että A:sta on nyt tullut polymorfinen, koska se voi pitää sisällään sekä A:ta että B:tä. Tämä synnyttää tekniikan joustavien ohjelmistojen luomiseksi, joka tunnetaan nimellä ohjelmointi rajapintaa kuin toteutusta varten, jossa käytetään aina vanhemman luokan tai rajapinnan muuttujia ydinalgoritmin määrittelyyn.
Hyöty tästä on se, että mikä tahansa uusi luokka, joka laajentaa vanhemman luokan, pääsee käsiksi kyseiseen algoritmiin.
Tässä on esimerkki luokan laajentamisesta Javassa:
class A { public void näytä() { System.out.println("näytä"); }}class B extends A { public void näytä() { System.out.println("näytä"); } } public void näytä() { System.out.println("parempi näytä"); }}public class Main { public static void main(String args) { A a = new B(); // mahdollista, koska B extends A a.show(); // tämä kutsuu nyt luokan B show()-metodia }}Outputbetter show
Voit nähdä, että laajentamalla luokkaa A, B:llä on nyt pääsy show()-metodiin, se voi jopa ohittaa show()-metodin käyttäytymisen, mikä tunnetaan metodin ohittamisena Javassa. Tämä valtava voima saadaan käyttämällä extends-avainsanaa.
Voit myös lukea Head First Design Pattern in Java -kirjasta lisätietoja tekniikasta, jossa ohjelmoidaan enemmän rajapintaa kuin toteutusta varten. Kirja on myös hiljattain päivitetty kattamaan Java SE 8.
Mitä tarkoittaa rajapinnan toteuttaminen
Rajapinnan toteuttamisen merkitys ei ole kovin erilainen kuin luokan laajentaminen, mutta siihen liittyy yksi varoitus. Kun luokka toteuttaa rajapinnan, sen on tarjottava kaikkien rajapinnan sisällä ilmoitettujen metodien toteutus. Jos se ei halua tarjota kaikkia toteutuksia, se voi julistautua abstraktiksi luokaksi.
Jos näitä sääntöjä ei noudateta, ohjelmasi ei voi kääntyä. Java-koodissa on monia esimerkkejä rajapinnan toteuttamisesta, mutta uskon, että Runnable-luokan toteuttaminen on suosituin. Tätä käytetään luomaan Runnable-tehtävä, jonka voi suorittaa säie.
class R implements Runnable{public void run(){ System.out.println("älä tee mitään"); }}
R-olion instanssi voidaan nyt välittää mihin tahansa metodiin, joka odottaa Runnable-oliota, kuten voit välittää sen ExecutorService-luokan execute()- ja submit()-metodeihin suorittaaksesi kyseistä tehtävää säiepooliin. Koska luokkamme on toteuttanut ainoan Runnable-rajapinnan metodin run(), se on konkreettinen luokka. Jos se ei olisi toteuttanut run()-metodia, siitä on tehtävä abstrakti lisäämällä abstract-avainsana classin eteen, esim.
abstrakti luokka R toteuttaa Runnable{}
Tärkeitä kohtia
Tässä on joitakin tärkeitä kohtia, jotka liittyvät extends- ja implements-avainsanaan Javassa:
1) Luokka voi vain laajentaa toista luokkaa Javassa, extends-avainsanan käyttö rajapinnan kanssa johtaa kääntämisvirheeseen kuten alla on esitetty:
rajapinta I{}class A{}class B extends A{}class C extends I{}
Kun käännät tämän lähdetiedoston, saat seuraavan virheen:
$ javac Main.javaMain.java:27: no interface expected hereclass C extends I{^1 error
2) Luokka voi laajentaa vain yhtä luokkaa, jos yrität laajentaa useampaa kuin yhtä luokkaa, saat taas kääntämisvirheen, kuten alla näkyy:
class C extends A, B{}$ javac Main.javaMain.java:27: '{' expectedclass C extends A, B{^1 error
3) Rajapinta voi käyttää extends-avainsanaa luodaksesi alarajapintoja Javalla esim.g. seuraava on täysin laillista Javassa
rajapinta J extends I{}
4) Rajapinta voi jopa laajentaa useita rajapintoja käyttämällä extends-avainsanaa kuten alla on esitetty:
rajapinta k extends I, J{}
5) Luokka voi käyttää implements-avainsanaa toteuttaakseen yhden tai useamman rajapinnan Javassa kuten alla on esitetty:
luokka D toteuttaa I, J, K{}
6) Luokka voi myös käyttää sekä extends- että implements-avainsanaa yhdessä laajentaakseen luokan ja toteuttaakseen rajapinnan, se on melko yleistä Javassa kuten seuraavassa esimerkissä näkyy:
class E extends A implements I, J{}
Kun luokka tekee näin, se on nyt A:n aliluokka ja I:n ja J:n alirajapinta, mikä tarkoittaa, että voit käyttää luokan E ja rajapinnan I, J viitemuuttujaa luokan E objektin tallentamiseen, kuten alla näkyy:
I i = new E();J j = new E();A a = new E();
Tämä antaa luokalle E valtavan vallan periytymisen ja polymorfismin käytössä.
7) Viimeisenä mutta ei vähäisimpänä, rajapinta ei voi käyttää implements-avainsanaa rajapinnan toteuttamiseen, se on laitonta Javassa ja kääntäjä heittää virheen kuten alla on esitetty:
rajapinta L toteuttaa J{}javac Main.javaMain.java:49: '{' odotetturajapinta L toteuttaa J{^1 virhe
Tässä kaikki extends- ja implements-avainsanojen välisestä erosta Javassa. On selvää, että extends-sanaa käytetään yleensä luokan laajentamiseen ja implements-sanaa käytetään yleensä rajapinnan toteuttamiseen. Vaikka on muitakin hienouksia, esim. rajapinta voi myös laajentaa toista rajapintaa tullakseen alirajapinnaksi, luokka voi myös olla abstrakti vaikka toteuttaisi rajapinnan, mutta se, mikä ei muutu, on se, että molempia käytetään vanhempi-lapsi-suhteen luomiseen Javassa.
Jos luokka B laajentaa toista luokkaa A, siitä tulee sen lapsia ja luokasta A tulee vanhempi. Sama pätee myös rajapinnan kohdalla. Voit edelleen lukea Head First Java ja Head First Object-Oriented Analysis oppiaksesi lisää oliokeskeisen ohjelmoinnin perusrakennuspalikoista Javassa.
Muut Java-haastattelukysymykset, joista saatat pitää
- Aggregoinnin, assosioinnin ja komposition välinen ero Javassa? (vastaus)
- Ero abstraktin luokan ja rajapinnan välillä Javassa? (vastaus)
- Ero periytymisen ja polymorfismin välillä Javassa? (vastaus)
- Ero abstraktion ja polymorfismin välillä Javassa? (vastaus)
- Miksi kompositio on parempi kuin periytyvyys Javassa? (artikkeli)
- Ero staattisten ja ei-staattisten muuttujien välillä Javassa? (vastaus)
- Miksi abstrakti luokka on tärkeä Javassa? (mielipide)
Jatko-opiskelu
Täydellinen Java-mestarikurssi
Javan perusteet: Java-kieli
Java syvällisesti: Become a Complete Java Engineer!