Java och Objektorienterad programmering

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

Historik

Det första objektorienterade programspråket var Simula-67. Språket konstruerades av Ole-Johan Dahl och Kristen Nygaard vid Norsk Regnesentral. Programspråket byggde på Algol 60 och var avsett för simulering. Det hade de flesta av de egenskaper som man idag förknippar med objektorienterad programmering; till exempel garbage collection (automatisk minneshantering), arv och klasser.

Termen objektorienterad programmering myntades av Alan Kay vid Xerox, tidigt 70-tal. Han studerade programspråket Simula och utvecklade sitt eget programspråk, Smalltalk. Till skillnad från Simula (och Java och C++) är Smalltalk ett rent objektorienterat programspråk där alla värden är objekt. De första grafiska användargränssnitten skrevs i Smalltalk (och i Lisp).

Ett av de mest kända objektorienterade programspråken är C++. Det konstruerades av Bjarne Stroustrup vid Bell Labs och fick sitt namn 1983. Programspråket bygger på C med idéer från Simula och Algol-68. En del begrepp är direkt tagna från Simula-67, till exempel nyckelordet 'virtual'. C++ skiljer sig från de flesta andra objektorienterade programspråken i att det saknar garbage collection—programmeraren måste se till att minnesutrymme som ej används längre avallokeras.

Jag kommer berätta mer om Java senare, men kortfattat: Java utvecklades vid Sun Microsystems av James Gosling och presenterades 1995.

Objektorientering

Vi talar om

De här begreppen är förstås sammankopplade: objektorienterade programspråk är konstruerade för att göra det lättare att använda OOP i sitt program. Man kan använda ett objektorienterat programspråk för att skriva program som inte följer principerna för OOP, å andra sidan är det också möjligt att skriva ett objektorienterat program i ett programspråk som inte har utformats för att stöda OOP.

En Dum Fråga

Vad vill vi åstadkomma med programspråk och nya utvecklingsmodeller? Alltså: varför håller vi överhuvud taget på och diskuterar de här sakerna?

Svar på dum fråga...

Förhoppningen är förstås att nya programspråk och nya utvecklingsmodeller ska hjälpa oss när vi skriver program. Några allmänna (och ganska självklara) önskemål är att

Det kan vara bra att ha de här sakerna i åtanke när du läser om olika programspråk, utvecklingsmodeller eller principer för hur man utformar program. När man tar fram ett programspråk eller utvecklar olika principer för programutveckling är ju målet att de ska hjälpa oss att skriva program.

Egna erfarenheter

Här är ett bra tillfälle att reflektera över egna erfarenheter. Har du själv deltagit i nåt större projekt?

Några begrepp

Några ideér som fanns före OOP men blivit en del av OOP:

Abstraktion

Låt oss börja med några exempel. I ett programspråk har vi konstruktioner för aritmetik, proceduranrop, hantering av filsystem, I/O etc.

Vi kan till exempel använda oss av och resonera om en operation som:

x + y

utan att veta något om hur den implementeras. Beroende på processor, kompilator och typ hos variablerna kan den här operationen implementeras på en lång rad olika sätt.

Från datorns synvinkel finns ju inga tal, bara ettor och nollor—men egentligen finns ju inte de heller, det enda vi har är ju elektriska signaler på olika spänningsnivåer...

På samma sätt talar vi om filer som om de var verkliga fysiska objekt, men i själva verket har vi ju bara några magnetiserade skivor (om filen lagras på en hårddisk).

Så en abstraktion består av två saker:

Man kan säga att en abstraktion är ett begrepp som man kan resonera om oberoende av den underliggande implementationen.

En abstraktion kan vara baserad på begrepp som kommer från applikationsdomänen, på matematiska koncept, eller något som man tagit fram som en del av implementationsarbetet.

Vid utveckling av komplexa system är det ofta lämpligt att introducera abstraktioner på olika nivåer.

Under kursens gång kommer vi att stöta på ett antal exempel på abstraktioner.

Modularitet (Enligt Meyer)

Vi kan titta på ett program och fundera på hur väl de tre sista punkterna är uppfyllda. Måste man studera hela programmet för att förstå det, eller kan en del av programmet förstås utan att man tittar på resten? Vad händer när problemspecifikationen ändras? Hur svårt är det att lokalisera fel?

Inkapsling

Inkapsling är mekanismer i programspråket för att dölja implementationen av en komponent. Jag kommer att prata om inkapsling i Java.

Software engineering

Begreppet myntades i en NATO-konferens 1968.

Man tyckte sig se ett problem ("Software crisis") som yttrade sig i att programutvecklingsprojekt ofta tog för lång tid att genomföra och att resultaten var ofta mindre lyckade.

Man uppfattade att traditionella ingenjörsprojekt (tex brobyggen, tunnelbyggen, mekaniska konstruktioner) fungerade bättre och ville utnyttja liknande principer i programutveckling.

Principer för OOP (Alan Kay)

Alan Kay som uppfann programspråket Smalltalk var den förste som pratade om objektorienterad programmering. Han definierade OOP med dessa punkter:

(Alan Kay hade en ytterligare punkt som jag har valt att inte ta med.)

Alla utom den första punkten gäller även Java. Jag skulle även vilja lägga till dessa:

Exempel

En person har två egenskaper, namn och ålder. Vi definierar en metod hello() som skriver ut en kort hälsning med personens namn och ålder.

Konstruktorn (som har samma namn som klassen) skapar och initialiserar objekt.

(Var inte orolig om du inte förstår alla detaljer i exemplet; allt kommer att förklaras noggrannare senare.)

public class Person {

    private String name;
    private int age;

    public Person (String n, int a) {
        name = n;
        age = a;
    }

    public void hello() {
        System.out.println("Jag heter "+ name
        +" och är "+ age +" år gammal.");
    }
    public void setName (String n) {
        name = n;
    }
    public String getName () {
        return name;
    }

    public static void main (String arg[]) {
	Person olle = new Person ("Olle", 7);

	olle.hello();
    }
}

Metoden main kommer att köras när man startar programmet. Vi börjar med att skapa en person Olle (personen heter "Olle" och är bunden till en variabel olle. Vi skickar meddelandet hello() till Olle.

Viktiga koncept:

Kommunicera med objekt

Exempel: Skapa en person.

Person olle = new Person ("Olle", 7);

Skicka ett meddelande till personen:

olle.hello();

Detta ger följande utskrift:

Jag heter Olle och är 7 år gammal.

OOP i sammanhang

Vad är OOP?

Exempel på icke-OO:

Ytterligare begrepp: Arv

Skapa en klass Employee som representerar anställda. Denna klass ärver av klassen Person.

public class Employee extends Person {
    private int salary;

    public Employee (String n, int a, int s) {
        super(n, a);
        salary = s;
    }
    public void setSalary (int s) { ... }
    public int getSalary () { ... }
}

Arv, exempel

Ett enkelt exempel. En anställd som heter John, är 23 år gammal och tjänar 123456 (vi vet dock inte i vilken valuta).

Employee john = new Employee("John", 23, 123456);

Skicka meddelandet hello().

john.hello();

Höj hans lön till 1234567.

john.setSalary(1234567);

Vi kan ändra klassen Employee och ge metoden hello() en definition i Employee (naturligtvis vill varje anställd tala om vad han eller hon tjänar):

public void hello() {
    super.hello();
    System.out.println("Jag tjänar "+ salary);
}

Denna metod anropar först super.hello() dvs metoden med samma namn i Person. Sedan skriver vi ut den anställdes inkomst.

Med denna definition ger meddelandet

john.hello();

utskriften

Jag heter John och är 23 år gammal.
Jag tjänar 123456

Polymorfi:

Anta att vi har fler klasser (Student, Teacher, ...) som alla ärver av klassen Person samt en array av personer:

Person[] alla = new Person[10];

alla[0] = olle; alla[1] = john;
...

for(int i = 0; i<10; i++){
    alla[i].hello();
}

Vad händer när man skickar meddelandet hello() till de olika objekten?

Den allmänna regeln är: Objektet "vet" vilken klass det tillhör.

Därmed vet objektet också vilken metod som ska anropas. Detta gör att en medlem av klassen Employee utför metoden som är definierad för den klassen (och berättar om vad han eller hon tjänar).

Vi kan ha olika definitioner av hello() i de olika klasserna. När ett visst objekt tar emot meddelandet utförs motsvarande metod.