I et av intervjuene mine ble jeg bedt om å forklare forskjellen mellom et grensesnitt og en abstrakt klasse.
Her er svaret mitt:
Metoder for et Java-grensesnitt er implisitt abstrakte og kan ikke ha implementeringer. En abstrakt Java-klasse kan ha instansmetoder som implementerer en standard oppførsel.
Variabler deklarert i et Java-grensesnitt er som standard endelige. En abstrakt klasse kan inneholde ikke-finale variabler.
Medlemmer av et Java-grensesnitt er som standard offentlige. En Java-abstrakt klasse kan ha de vanlige smakene av klassemedlemmer som private, protected osv.
Et Java-grensesnitt skal implementeres ved hjelp av nøkkelordet "implements"; A Java-abstrakt klasse bør utvides ved hjelp av nøkkelordet "extends".
Et grensesnitt kan bare utvide et annet Java-grensesnitt, en abstrakt klasse kan utvide en annen Java-klasse og implementere flere Java-grensesnitt.
En Java-klasse kan implementere flere grensesnitt, men den kan bare utvide bare én abstrakt klasse.
Intervjueren var imidlertid ikke fornøyd, og fortalte meg at denne beskrivelsen representerte "boklig kunnskap".
Han ba meg om et mer praktisk svar og forklarte når jeg ville velge en abstrakt klasse fremfor et grensesnitt, ved hjelp av praktiske eksempler.
Hvor gjorde jeg feil?
Ingenting er perfekt her i verden. De hadde kanskje forventet en mer praktisk tilnærming.
Men etter forklaringen din kan du legge til disse linjene med en litt annen tilnærming.
Grensesnitt er regler (regler fordi du må gi en implementering til dem som du ikke kan ignorere eller unngå, slik at de pålegges som regler) som fungerer som et felles forståelsesdokument blant forskjellige team i programvareutvikling.
Grensesnitt gir ideen om hva som skal gjøres, men ikke hvordan det skal gjøres. Så implementering avhenger helt av utvikleren ved å følge de gitte reglene (betyr gitt signatur av metoder).
Abstrakte klasser kan inneholde abstrakte erklæringer, konkrete implementasjoner eller begge deler.
Abstrakte erklæringer er som regler som skal følges, og konkrete implementeringer er som retningslinjer (du kan bruke den som den er, eller du kan ignorere den ved å overstyre den og gi den din egen implementering).
Videre hvilke metoder med samme signatur som kan endre oppførselen i ulike sammenhenger, er gitt som grensesnittdeklarasjoner som regler som skal implementeres tilsvarende i ulike sammenhenger.
Endre: Java 8 gjør det enklere å definere standard og statiske metoder i grensesnittet.
public interface SomeInterfaceOne {
void usualAbstractMethod(String inputString);
default void defaultMethod(String inputString){
System.out.println("Inside SomeInterfaceOne defaultMethod::"+inputString);
}
}
Nå når en klasse vil implementere SomeInterface, er det ikke obligatorisk å gi implementering for standardmetoder for grensesnittet.
Hvis vi har et annet grensesnitt med følgende metoder:
public interface SomeInterfaceTwo {
void usualAbstractMethod(String inputString);
default void defaultMethod(String inputString){
System.out.println("Inside SomeInterfaceTwo defaultMethod::"+inputString);
}
}
Java tillater ikke å utvide flere klasser fordi det resulterer i "Diamond Problem" der kompilatoren ikke er i stand til å bestemme hvilken superklassemetode som skal brukes. Med standardmetodene vil diamantproblemet også oppstå for grensesnitt. Fordi hvis en klasse implementerer både
SomeInterfaceOne and SomeInterfaceTwo
og ikke implementerer den vanlige standardmetoden, kan ikke kompilatoren bestemme hvilken den skal velge. For å unngå dette problemet er det i java 8 obligatorisk å implementere felles standardmetoder for forskjellige grensesnitt. Hvis en klasse implementerer begge de ovennevnte grensesnittene, må den gi implementering for defaultMethod () -metoden, ellers vil kompilatoren kaste kompileringstidsfeil.
Forklaringen din ser anstendig ut, men det kan hende det så ut som om du leste alt fra en lærebok :-/ :-/.
Det jeg er mer opptatt av er, hvor solid var eksemplet ditt? Gadd du å ta med nesten alle forskjellene mellom abstrakt og grensesnitt?
Personlig vil jeg foreslå denne lenken: http://mindprod.com/jgloss/interfacevsabstract.html#TABLE
for en uttømmende liste over forskjeller...
Håper det hjelper deg og alle andre lesere i deres fremtidige intervjuer.
Et grensesnitt er en "kontrakt" der klassen som implementerer kontrakten lover å implementere metodene. Et eksempel der jeg måtte skrive et grensesnitt i stedet for en klasse, var da jeg oppgraderte et spill fra 2D til 3D. Jeg måtte lage et grensesnitt for å dele klasser mellom 2D- og 3D-versjonen av spillet.
package adventure;
import java.awt.*;
public interface Playable {
public void playSound(String s);
public Image loadPicture(String s);
}
Da kan jeg implementere metodene basert på miljøet, mens jeg fortsatt kan kalle disse metodene fra et objekt som ikke vet hvilken versjon av spillet som lastes inn.
offentlig klasse Adventure utvider JFrame implementerer Playable
public class Dungeon3D utvider SimpleApplication implementerer Spillbar
public class Main extends SimpleApplication implements AnimEventListener, ActionListener, Playable
I spillverdenen kan verden typisk være en abstrakt klasse som utfører metoder på spillet:
public abstract class World...
public Playable owner;
public Playable getOwner() {
return owner;
}
public void setOwner(Playable owner) {
this.owner = owner;
}