"Hej, Amigo! Här är ett ämne som jag tror att du kommer att använda mycket av. Jag pratar om arv. "

För den oinvigde är programmering som magi. Så låt mig börja med en analogi...

Anta att du är en magiker som vill skapa en flygande häst. Du kan försöka trolla fram en Pegasus. Men eftersom flygande hästar inte är naturligt förekommande kommer du att ha det riktigt svårt. Du skulle ha mycket att göra. Det skulle vara mycket lättare att börja med en häst och kalla fram några vingar.

Arv.  Fördelar med arv - 1

I programmering kallar vi denna process för "arv" . Anta att du behöver skriva en mycket komplex klass. Du kan spendera lång tid på att skriva kod från början och sedan utföra långa tester för att hitta buggar. Men varför göra det på den hårda vägen? Det är bättre att titta runt och se om klassen du letar efter redan finns?

Låt oss säga att du hittar en klass som implementerar 80 % av den funktionalitet du behöver. Du kan bara kopiera dess kod till din klass. Men det skulle ha flera nackdelar:

1) Klassen du hittar kanske redan är kompilerad till bytecode. Du kanske inte har tillgång till dess källkod.

2) Du kanske har källkoden för klassen, men jobbar också på ett företag som kan bli stämt för ett par miljarder om du använder ens 6 rader av någon annans kod. Och då kommer de att stämma dig.

3) Detta leder till onödig duplicering av massor av kod. Och om författaren till den andra klassen hittar en bugg och fixar den, har du fortfarande felet.

Det finns en mer elegant lösning som inte kräver att man skaffar lagligt tillstånd till originalklassens kod. I Java kan du helt enkelt förklara den andra klassen som förälder till din klass. Detta motsvarar att lägga till den klassens kod till din egen klass. Alla data och metoder för den överordnade klassen kommer att visas i din klass. Till exempel kan du ärva från en «häst», lägga till «vingar» och få en «Pegasus».

Arv.  Fördelar med arv - 2

"Mycket intressant. Snälla fortsätt."

"Arv har andra användningsområden också. Anta att du har tio klasser som är väldigt lika. De har matchande data och metoder. Du kan skapa en speciell basklass , flytta data (och associerade metoder) till basklassen och ha de tio klasserna ärva från den. Med andra ord, för varje klass anger du att den har en överordnad klass, även känd som en basklass."

"Precis som fördelarna med abstraktion bara avslöjas i samband med inkapsling, förstoras fördelarna med arv av polymorfism. Men jag ska berätta om det i morgon. Låt oss idag titta på några exempel på arv."

"Anta att vi skriver ett schackprogram. Vi behöver lektioner för schackpjäserna. Vilka klasser skulle du föreslå, Amigo?"

"Kung, drottning, biskop, riddare, torn och bonde."

"Mycket bra. Du har inte missat någonting."

"Och vilken data skulle du föreslå att lagra i dessa klasser?"

"Varje pjäs brädposition (x och y) och värde. Trots allt är vissa pjäser mer värda än andra."

"Och vad är skillnaderna mellan dessa klasser?"

"De skiljer sig åt i hur de flyttar pjäserna. I deras beteende."

"Ja. Du kan definiera dem som klasser så här:"

class King
{
int x;
int y;
int worth;
void kingMove()
{
//code that defines,
//how the king moves
}
}
class Queen
{
int x;
int y;
int worth;
void queenMove()
{
//code that defines,
//how the queen moves
}
}
class Rook
{
int x;
int y;
int worth;
void rookMove()
{
//code that defines,
//how the rook moves
}
}
class Knight
{
int x;
int y;
int worth;
void knightMove()
{
//code that defines,
//how the knight moves
}
}
class Bishop
{
int x;
int y;
int worth;
void bishopMove()
{
//code that defines,
//how the bishop moves
}
}
class Pawn
{
int x;
int y;
int worth;
void pawnMove()
{
//code that defines,
//how the pawn moves
}
}

"Ja, det är precis så jag skulle skriva det."

"Men titta på hur du kan använda arv för att skriva mindre kod. Vi kan flytta identiska metoder och data till en gemensam klass. Låt oss kalla det ChessItem. Det är inte vettigt att skapa ChessItem-objekt, eftersom de inte motsvarar någon schackpjäs. Men klassen skulle vara oerhört hjälpsam:"

class King extends ChessItem
{
void kingMove()
{
//code that defines,
//how the king moves
}
}
class Queen extends ChessItem
{
void queenMove()
{
//code that defines,
//how the queen moves
}
}
class Rook extends ChessItem
{
void rookMove()
{
//code that defines,
//how the rook moves
}
}
 class ChessItem
{
int x;
int y;
int worth;
}
 
class Knight extends ChessItem
{
void knightMove()
{
//code that defines,
//how the knight moves
}
}
class Bishop extends ChessItem
{
void bishopMove()
{
//code that defines,
//how the bishop moves
}
}
class Pawn extends ChessItem
{
void pawnMove()
{
//code that defines,
//how the pawn moves
}
}

"Så intressant!"

"Absolut! Fördelen är särskilt stor i projekt som innehåller tusentals olika objekt och hundratals klasser. I det här fallet kan korrekt valda klasser inte bara avsevärt förenkla logiken, utan också minska den nödvändiga koden med en faktor tio."

"Så vad måste du göra för att ärva en klass?"

"Efter att ha deklarerat en klass använder vi nyckelordet " förlänger ", följt av namnet på den överordnade klassen. Du kan bara ärva från en klass. "

Arv.  Fördelar med arv - 3

Bilden visar en "ko" som har ärvt från en «gris». «Grisen» ärver från «kycklingen» och «kycklingen» ärver från «ägget». Varje klass har bara en förälder! Sådant arv är inte alltid logiskt. Om du bara har en gris, men du verkligen behöver en ko, kan programmerare ofta inte motstå önskan att göra en «ko» av «grisen».

"Men tänk om jag vill ärva från två klasser? Finns det något jag kan göra?!"

"Inte riktigt. Java-klasser stöder inte multipla nedärvning av implementering: en klass kan bara ha en enda förälderklass. Men det finns flera arv av typen, vilket betyder att en klass kan implementera mer än ett gränssnitt. Detta mildrar problemet något. "

"Jag förstår. Och vad är ett gränssnitt?"

"Jag ska berätta om gränssnitt imorgon. Låt oss nu fortsätta att fördjupa oss i arv."