Tyvärr används både extends och implements nyckelordet i Java för att implementera arvskonceptet i objektorienterad programmering, men det finns en subtil skillnad mellan dem. Nyckelordet extends används huvudsakligen för att utöka en klass, dvs. för att skapa en underklass i Java, medan nyckelordet implements används för att implementera ett gränssnitt i Java. Nyckelordet extends kan också användas av ett gränssnitt för att utvidga ett annat gränssnitt. För att bättre förstå skillnaden mellan extends och implements måste du också lära dig och förstå skillnaden mellan klass och gränssnitt i Java.
Och även om båda är en integrerad del av applikationsutvecklingen med hjälp av den objektorienterade metoden, är ett gränssnitt mer abstrakt än en klass och används därför för att definiera API eller kontrakt.
Å andra sidan tillhandahåller en klass den konkreta implementeringen av gränssnittet, dvs. den faktiska koden som utför jobbet. Även om en klass också kan vara abstrakt för att definiera ett kontrakt, är det ett gränssnitt i Java som bäst utför det jobbet. Till och med Joshua Bloch har i Effective Java gett råd om att använda gränssnitt för att deklarera typ i Java, eftersom det främjar flera arv i Java, vilket är begränsat jämfört med C++.
Även efter Java 8 stöds endast flera arv av typ och beteende i Java (genom att införa standardmetoder i Java 8), men flera arv av tillstånd stöds fortfarande inte. Om du vill veta mer om varför flera arv inte stöds i Java, se här.
Och om du är ny i Java-världen rekommenderar jag att du går igenom The Complete Java MasterClass på Udemy för att lära dig Java på ett bättre och mer strukturerat sätt. Detta är en av de bästa och mest uppdaterade kurserna för att lära sig Java online.
Vad är innebörden av att förlänga en klass
En klass i Java kan förlänga en annan klass för att bli en underklass. När klass B förlänger klass A blir B en underklass (barn) och A blir en överklass (förälder). En underklass kan återanvända alla funktioner från föräldraklassen och återanvändning av kod är en viktig anledning till att förlänga en klass, men få förstår att viktigare är det definierande förhållandet som senare utnyttjas genom polymorfism.
Till exempel, om klass B förlänger klass A kan en referensvariabel av typ A innehålla objektet B, vilket innebär att A nu blir polymorf eftersom den kan innehålla både A och B. Detta ger upphov till en teknik för att skapa flexibel programvara, känd som programmering för gränssnitt än implementering, där man alltid använder variabler i den överordnade klassen eller gränssnittet för att definiera kärnalgoritmen.
Fördelen med att göra detta är att alla nya klasser som förlänger den överordnade klassen kommer att ha tillgång till algoritmen.
Här är ett exempel på att förlänga en klass i Java:
class A { public void show() { System.out.println("show"); }}}class B extends A { public void display() { System.out.println("display"); } public void show() { System.out.println("better show"); }}}public class Main { public static void main(String args) { A a = new B(); // möjligt eftersom B extends A a.show(); // detta kommer nu att anropa show() metoden i klass B }}Outputbetter show
Du kan se att genom att förlänga klass A har B nu tillgång till show() metoden, den kan till och med åsidosätta beteendet hos show() metoden, vilket är känt som method overriding i Java. Denna enorma makt kommer genom att använda nyckelordet extends.
Du kan också läsa Head First Design Pattern in Java för att lära dig mer om tekniken att programmera för gränssnitt än för implementering. Boken är också nyligen uppdaterad för att täcka Java SE 8.
Vad är innebörden av att implementera ett gränssnitt
Betydelsen av att implementera ett gränssnitt skiljer sig inte särskilt mycket från att förlänga en klass, men det kommer med ytterligare ett förbehåll. När en klass implementerar ett gränssnitt måste den tillhandahålla en implementering av alla metoder som deklarerats i gränssnittet. Om den inte vill tillhandahålla all implementering kan den deklarera sig själv som en abstrakt klass.
Om den inte följer dessa regler innebär det att ditt program inte kan kompileras. Det finns många exempel på att implementera ett gränssnitt i Javakod, men jag tror att implementering av Runnable är det mest populära. Detta används för att skapa en Runnable-uppgift som kan exekveras av en tråd.
class R implements Runnable{public void run(){ System.out.println("do nothing"); }}
En instans av R kan nu skickas till vilken metod som helst som förväntar sig en Runnable, t.ex. kan du skicka den här till både execute() och submit()-metoden i ExecutorService-klassen för att köra den uppgiften i en trådpool. Eftersom vår klass har implementerat metoden run(), den enda metoden från gränssnittet Runnable, är den en konkret klass. Om den inte hade implementerat metoden run() måste du göra den abstrakt genom att lägga till nyckelordet abstrakt framför class, t.ex.
abstrakt klass R implements Runnable{}
Väsentliga punkter
Här är några av de viktiga punkter som rör nyckelorden extends och implements i Java:
1) En klass kan endast förlänga en annan klass i Java, användning av extends nyckelordet med gränssnittet kommer att resultera i ett kompileringsfel som visas nedan:
gränssnitt I{}klass A{}klass B förlänger A{}klass C förlänger I{}
När du kompilerar den här källfilen kommer du att få följande fel:
$ javac Main.javaMain.java:27: no interface expected hereclass C extends I{^1 error
2) En klass kan bara förlänga en klass, om du försöker förlänga fler än en klass kommer du återigen att få ett kompileringsfel som visas nedan:
class C extends A, B{}$ javac Main.javaMain.java:27: '{' expectedclass C extends A, B{^1 error
3) Ett gränssnitt kan använda nyckelordet extends för att skapa undergränssnitt i Java, till exempel.g. Följande är helt lagligt i Java
interface J extends I{}
4) Ett gränssnitt kan till och med förlänga flera gränssnitt genom att använda nyckelordet extends som visas nedan:
interface k extends I, J{}
5) En klass kan använda nyckelordet implements för att implementera ett eller flera gränssnitt i Java som visas nedan:
class D implements I, J, K{}
6) En klass kan också använda både extends- och implements-nyckelordet tillsammans för att utöka en klass och implementera ett gränssnitt, det är ganska vanligt i Java som visas i följande exempel:
class E extends A implements I, J{}
När en klass gör det är den nu en underklass till A och ett undergränssnitt till I och J, vilket innebär att du kan använda en referensvariabel av klass E och gränssnittet I, J för att lagra ett objekt av klass E som visas nedan:
I i = new E();J j = new E();A a = new E();
Detta ger klass E en enorm kraft när det gäller att använda arv och polymorfism.
7) Sist men inte minst kan ett gränssnitt inte använda nyckelordet implements för att implementera ett gränssnitt, det är olagligt i Java och kompilatorn kommer att kasta ett fel som visas nedan:
interface L implements J{}javac Main.javaMain.java:49: '{' expectedinterface L implements J{^1 error
Det är allt om skillnaden mellan extends- och implements-nyckelorden i Java. Det är tydligt att extends i allmänhet används för att utöka en klass och implements i allmänhet används för att implementera ett gränssnitt. Det finns visserligen fler finesser, t.ex. kan ett gränssnitt också förlänga ett annat gränssnitt för att bli ett undergränssnitt, en klass kan också vara abstrakt även efter att ha implementerat ett gränssnitt, men det som inte förändras är att de båda används för att skapa förälder-barn-förhållandet i Java.
Om klass B förlänger en annan klass A blir den dess barn och klass A blir en förälder. Samma sak gäller för gränssnittet. Du kan vidare läsa Head First Java och Head First Object-Oriented Analysis för att lära dig mer om de grundläggande byggstenarna i objektorienterad programmering i Java.
Andra intervjufrågor om Java som du kanske gillar
- Skillnaden mellan Aggregation, Association och Komposition i Java? (svar)
- Skillnaden mellan abstrakt klass och gränssnitt i Java? (svar)
- Skillnaden mellan arv och polymorfism i Java? (svar)
- Skillnaden mellan abstraktion och polymorfism i Java? (svar)
- Varför är komposition bättre än ärftlighet i Java? (artikel)
- Skillnaden mellan statiska och icke-statiska variabler i Java? (svar)
- Varför är abstrakta klasser viktiga i Java? (åsikt)
Fortsatt lärande
Complete Java Masterclass
Java Fundamentals: Java-språket
Java på djupet: Bli en komplett Java-ingenjör!