Klasser och arv

Sven-Olof Nyström
OOP med Java våren -25
Informationsteknologi
Uppsala Universitet

Arv

En klassdefinition

class A extends B { ... }

definierar en klass A som ärver av B.

Här gäller:

Ett exempel

Anta att vi vill definiera fyra klasser:

En bil är förstås ett slags motorfordon, varje motorfordon är också ett fordon och en cykel är också ett fordon (men inte ett motorfordon).

Vi antar att bilar och cyklar har en toppfart. För att göra exemplet intressantare antar vi att:

Klassen Fordon definierar inga metoder eller instansvariabler:

class Fordon {
}

Klassen Motorfordon ärver av Fordon. Här introduceras en instansvariabel toppfart samt en metod getToppfart.

Konstuktorn tar ett argument t (toppfart) och tilldelar instansvariabeln detta värde.

class Motorfordon extends Fordon {
    private double toppfart;
    Motorfordon (double t) {
        toppfart = t;
    }
    double getToppfart() {
        return toppfart;
    }
}

Klassen Bil ärver av MotorFordon. Vi lägger till två instansvariabler, antal_hjul och motorstyrka.

Konstruktorn tar två argument, m (motorstyrka) och h (antal hjul), tilldelar instansvariablerna dessa värden samt anropar superklassens konstruktor med motorstyrka gånger 1.5.

class Bil extends Motorfordon {
    int motorstyrka;
    int antal_hjul;
    Bil(int m, int h){
        super(m * 1.5);
//Antar att toppfarten är motorstyrkan * 1.5

        motorstyrka = m;
        antal_hjul = h;
    }
}

Klassen Cykel har en instansvariabel, cyklist.

Konstruktorn tar en person (dvs ett objekt av klassen Person) som argument och tilldelar instansvariabeln cyklist detta värde.

Klassen Person har ni redan sett, men här kommer den igen:

   class Person {
       int ålder;
       String namn;
   }

Metoden getToppfart definieras så att den beror av cyklistens ålder.

(Låt mig här be alla äldre cyklister om ursäkt—exemplet är larvigt men jag har inte kommit på nåt bättre...)

Det intressanta är att toppfarten för cyklar beräknas varje gång metoden anropas, till skillnad från motsvarande definition i klassen Motorfordon.

class Cykel extends Fordon {
    private Person cyklist;
    Cykel (Person p) {
        cyklist = p;
    }
    double getToppfart () {
        if (cyklist.ålder > 60) return 10;
        if (cyklist.ålder > 25) return 20;
        return 30; //Larvigt...
    }
}

I många andra objektorienterade programspråk kan man skapa ett objekt men glömma att initiera det. Det är en ganska vanlig källa till buggar, så Javas designers försökte ta bort denna felkälla genom att införa konstruktorer,

Användning av arv

Hur kan klasser kan relateras genom arv?

Som ni har sett betyder arv att en klass ärver implementation av en annan.

I ett välskrivet program bör arv endast användas när klasserna är konceptuellt relaterade.

I exemplet gäller det ju att

Rekommendation

En god tumregel är att endast använda arv när

Gemensam superklass

Det händer ofta att man har två klasser som verkar vara relaterade på nåt sätt men det passar ändå inte att låta en av dem ärva från den andra.

Exempel: Anta att du har två klasser, Bil och Cykel. Det är ju uppenbart att klasserna har nåt gemensamt, men man kan inte säga att bilar är en slags cyklar (eller tvärtom).

Lösningen är vanligtvis att introducera en ny klass som rymmer gemensamma datastrukturer och metoder och som båda klasserna får ärva ifrån. I exemplet har vi förstås en klass Fordon.

Två sätt att tänka på objektorienterade program

När man resonerar om ett objektorienterat program måste man tänka på två sätt:

Notera: Klassen som beskriver bilar heter "Bil" eftersom varje instans av klassen beskriver en bil. Låt inte en klass ha ett namn i plural—till exempel "Bilar" eller "Cyklar".

Frågor om arv

För att besvara frågorna nedan blir du tvungen att gå utanför anteckningarna. Kolla i kursboken eller på nätet. Det kan också hjälpa att skriva enkla testprogram för att kontrollera att din förståelse är korrekt.