TDDE10 - Objektorienterad programmering i Java

Från Studieboken - Skapad av och för studenter
Version från den 23 december 2019 kl. 16.32 av User1 (Diskussion | bidrag)

Hoppa till: navigering, sök
TDDE10
Institution Institutionen för datavetenskap
Examinator Erik Nilsson
Examination Datorentamen (1 hp)
Laborationskurs (3 hp)
Programmeringsprojekt (2 hp)
Högskolepoäng 6 hp

Om kursen

TDDE10, Objektorienterad programmering i Java, är en ny kurs för vårterminen 2017. Den ersätter den tidigare kursen i Java för Industriell ekonomi med kurskod TDDC30. Se sidan för TDDC30 - Programmering i Java, datastrukturer och algoritmer för material om Java.

Java

Java är ett av världens mest använda programmeringsspråk, just för dess operativsystemsneutralitet. I programspråket ADA som kursen TDDD11 undervisas i så använder man en kompilator som tolkar den källkod som programmeraren skrivit och gör om den till maskinkod som datorn kan köra. I Java så finns det ett mellanlager som kallas för Java Virtual Machine (JVM). JVM gör det möjlig att köra samma javakod på alla operativsystem som har stöd för detta, vilket i stort sett gör språket plattformsoberoende, det går lika bra att köra javakod i en Androidtelefon som på en Mac.

Språket är uppbyggt på klasser som på olika sätt kommunicerar och interagerar med varandra.
Wikipediaartikeln

Konstruktorer

Varje gång man skriver en ny klass så skapas en konstruktor, skriver man ingen egen så skapas automatiskt en tom utan inparametrar. Konstruktorn skrivs ungefär som en metod i klassen där metodnamnet är namnet på klassen. Den används sedan när man initierar klassen som ett objekt. Via konstruktorn kan man skicka med data som är bra vid skapandet av objektet. Skriver man t.ex klassen Human så är det rimligt att lägga namn och ålder som inparametrar i konstruktorn, då alla människor har ett namn och en ålder. I konstruktorn kan man också skriva kod som man vill ska köras varje gång som en klass instansieras.

Här är ett exempel på hur konstruktorn skrivs:

public class Cat { // Publika klassen Cat
     
     private String name; // Instansvariabel för kattens namn
     private int age;  // Instansvariabel för kattens ålder
     
     public Cat (String name, int age) { // Detta är huvudet av konstruktorn. Vi tar in kattens namn och ålder
          this.name = name; // Vi tilldelar instansvariabeln "name" med inparametern "name"s data
          this.age = age; // Vi tilldelar instansvariabeln "age" med inparametern "age"s data
          System.Out.println("The cat's name is " + name + " and the age of the cat is " + age); // Utskrift av namn och ålder
     }
}


När man sedan instansierar ett objekt av klassen Cat skriver man på följande sätt:

Cat kattenKalle = new Cat("Kalle", 10); // Vi skickar in namnet "Kalle" och åldern 10 i konstruktorn
Cat kattenPelle = new Cat("Pelle", 2); // Vi skickar in namnet "Pelle" och åldern 2 i konstruktorn


Wikipediaartikeln

Objektorientering

Objektorienterad programmering bygger på program som består av en uppsättning objekt som interagerar med varandra på olika sätt.

Objekt


Wikipediaartikeln

Klass

Java är ett objektorienterat språk som är uppbyggt på b.la klasser. En klass är ett eget kodstycke som är en mall man använder för att skapa ett objekt i Java. I klassen skriver man instruktioner om hur just den klassen/objektet fungerar. Instruktionerna (klassen) består av importering av paket, attribut och metoder. Se följande exempel:

package test; // Denna klass tillhör paketet "test"

// Detta är en kommentar. Kommentarer i Java skrivs med två stycken slash följt av en text
import java.grafisktpaket.* // Stjärnan (*) betyder att vi importerar precis alla klasser i paketet grafisktpaket
import java.util.ArrayList; // Här hämtar vi enbart klassen "ArrayList". Det är viktigt att inte hämta onödiga klasser som inte används


private int nummer; // Här skapar vi en private integer (heltalsvariabel) med namnet nummer
private double nummer2; // Här skapar vi en private double (decimalvariabel) med namn nummer2
private String namn; // Här skapar vi en private String (textsträng) med namnet namn
private boolean check; // Här skapar vi en private boolean (tvåvärdesvariabel) med namn check


public class skrivText() { // Klassen heter skrivText och är public (dvs synlig för alla).
        System.out.println("Hello World!"); // Här skrivs "Hello World!" ut i konsolen.
}

För att skapa ett objekt så instansierar man en klass, detta görs i koden man vill skapa objektet. I nedanstående exempel instansierar vi klassen ArrayList. Detta sker i två steg:

  1. Skapa en referens som ska peka på ett objekt skapat kring en specifik klass.
  2. Instansiera själva objektet och peka referensen på objektet.


ArrayList<String> list; // Steg 1: Här skapar referensen "list" till ett ArrayList-objekt.
list = new ArrayList<String>(); // Steg 2. Här skapas själva ArrayList-objektet som referensen "list" pekar på.

Detta kan även göras genom att skriva ihop de två stegen:

ArrayList<String> list = new ArrayList<String>();


Wikipediaartikeln

Synlighet

Synlighet används för att begränsa insynen och dölja implementationen av klasser, metoder och attribut. Som regel ska man visa upp så lite som möjligt, endast det som verkligen är nödvändigt. Attribut är av god sed och vana private, därför måste man komma åt dem på något annat sett. Detta gör man via getters and setters. Getter är en metod som hämtar attributet, Setter är en metod som sätter ett nytt värde på attributet.

public class testMetod() {

     private int number = 0;

     public int getNumber() { // Getter returnerar integern number
          return number;
     }

     public void setNumber(int number) { // Setter sätter number till inparameterns värde
          this.number = number;
     }
}


Olika synlighet
Synlighet Klass Paket Subklass Värld
public Ja Ja Ja Ja
protected Ja Ja Ja Nej
private Ja Nej Nej Nej


God sed och vana
Klasser Som regel public. Används de endast internt kan mer begränsad synlighet användas
Metoder public
Interna metoder private
Attribut private (eventuellt protected om motivetat)

Statiska metoder och attribut

Om en metod eller ett attribut hör till hela klassen i sig än en specifik instans (objekt) så ska den göras statisk. De kallas då för klassmetoder och klassvariabeler. Ett exempel på detta skulle kunna vara i ett program där man har användning för vilket år det är. Det finns ingen mening att skapa ett nytt attribut med samma år för varje objekt som instansieras. När den görs statisk så lagras attributet enbart på ett minne som tillhör klassen i sig, det vill säga oavsett hur många objekt av klassen som instansieras så skapas bara ett minnesutrymme för attributet. Detta betyder också att man kan kalla på attributet från andra klasser i samma paket utan att instansiera klassen som ett objekt.

public class Program {
     public static int year = 2016; // Statiskt attribut
}

public class OtherProgram { // Klassen otherProgram ligger i samma paket som Program
     int currentYear = Program.year; // Vi tilldelar variabeln currentYear värdet 2016 genom att kalla på klassvariabeln year i klassen Program
     System.Out.println(currentYear); // Detta kommer att skriva ut 2016 på skärmen
}

Arv och polymorfism

Arv är en stor del av objektorienterad programmering. Varje klass består av instruktioner i form av metoder och attribut. Säg att vi har en klass som heter Dog. Varje hund måste kunna äta, gå och sova, så metoderna eat(), walk() och sleep() känns nödvändiga. Men vi nöjer oss inte med att vara så generella som att enbart ha en klass för alla hundar, utan vi vill skapa en specifik klass för just Golden Retrievers, så vi skapar klassen GoldenRetriever som ärver från klassen Dog. Nu är vår klass Dog en superklass och vår klass GoldenRetriever en subklass till Dog. En Golden Retriever gillar en viss typ av mat som andra hundar inte gillar, därför måste vi skriva en ny unik metod av eat() i vår nya subklass. Det vi nu gör kallas för att överskugga (override) en metod. När vi nu kallar på metoden eat() för ett GoldenRetriever-objekt så kommer den klasspecifika metoden att köras och inte den generella i klassen Dog. Däremot om vi kallar på metoden sleep() för ett GoldenRetriever-objekt så kommer den generella metoden för klassen Dog köras, då alla hundar sover på samma sätt och ingen ny klasspecifik metod har skrivits. Det är alltså möjligt att kalla på samtliga metoder i superklassen. Väljer man däremot att skriva över metoden med en subklass-specifik metod så körs den istället.

Klassen Dog

public class Dog { 

     public void eat() {
          .....
     }

     public void walk() {
          .....
     }

     public void sleep() {
          .....
     }
}


Klassen GoldenRetriever

public class GoldenRetriever extends Dog { // För att ärva från en annan klass skriver man "... extends KLASSNAMN" 

     private int age = 7;

     public void eat() { // Metoden overridear metoder eat() i klassen Dog
          .....
     }

     public int getAge() {
          return age;
     }
}

Om man vill tvinga fram att en subklass måste implementera vissa specifika metoder från dess superklass så gör man de metoderna abstrakta i superklassen. Har man en abstrakt metod i sin superklass så blir hela superklassen abstract. En abstrakt klass kan inte instansieras. I fallet ovan skulle metoden eat() kunna vara ett exempel på en metod som kan vara bra att göra abstrakt, då alla hundar äter olika typ av mat.

Abstrakta klassen Dog

public abstract class Dog { // Klassen Dog är abstrakt och kan inte instansieras

     public abstract void eat(String food); // Metoden är abstrakt och måste implementeras av varje klass som ärver av klassen Dog

     public void walk() {
          .....
     }

     public void sleep() {
          .....
     }
}


Polymorfism kommer från grekiskan poly-morf som betyder många former. Säg att vi skriver en metod och vet att vi kommer att få in en hund som inparameter, men inte exakt vilken hund (subklass), det kanske är en Golden Retriever, eller en Tax. I detta fallet så använder vi polymorfism. Då skriver du enbart klassen Dog som inparameter och lämnar det öppet exakt vilken hund-typ som kommer att skickas in. Det är inte förens i körögonblicket som det bestäms.

public class Kennel {
     public static void addDog (Dog dog) {
          .....
     }

     public static void main(String[] args) { 
          GoldenRetriever kalle = new GoldenRetriever(); // Vi skapar en ny GoldenRetriever
          Kennel.addDog(kalle); // Vi skickar in en GoldenRetriever in i addDog, vilket är okej då det är en subklass till Dog och är tillåtet enligt polymorfi
     }
}

Wikipediaartikeln

Loopar

En loop är ett kodstycke som i sin tur upprepar ett annat kodstycke ett visst antal gånger. Det finns egentligen två loopar som användes mycket i kursen: While-loop och For-loop.

While-loop
En While-loop används då man från början inte vet exakt hur många gånger loopen ska köras, men man kan med ett villkor bestämma det. Så länge villkoret är uppfyllt så körs loopen. Viktigt är att det finns en variabel i villkoret som förändras under varje loop, annars kommer loopen att gå i all evighet. Ett exempel kan vara att man letar efter ett visst värde i en lista, vi slutar loopen när vi hittat värdet. Det programmet kan se ut på följande sätt:

ArrayList<Integer> listOfNumbers = new ArrayList<Integer>(); // Vi skapar en ArrayList av Integers (siffror)

add.listOfNumbers(1); // Vi lägger till ett antal siffror i vår lista
add.listOfNumbers(2);
add.listOfNumbers(3);
add.listOfNumbers(4);
add.listOfNumbers(5);

private int counter = 0;

while (listOfNumbers(counter) != 3) {
     ++counter;
}

System.Out.println(counter); // Siffran 3 kommer att skrivas ut i terminalen


(konceptet while-loop är samma för både programspråket C och Java)
Wikipediaartikeln


For-loop
For-loopen är en typ av While-loop, även den har ett villkor i sig och så länge som villkoret är uppfyllt så körs loopen. For-loopens huvud är uppdelat i tre delar:

  1. Deklaration av integer som används som en counter
  2. Villkor
  3. Hur countern ska förändras


Om vi skriver samma exempel som ovan, fast med en for-loop, skulle det kunna se ut såhär:

ArrayList<Integer> listOfNumbers = new ArrayList<Integer>(); // Vi skapar en ArrayList av Integers (siffror)

add.listOfNumbers(1); // Vi lägger till ett antal siffror i vår lista
add.listOfNumbers(2);
add.listOfNumbers(3);
add.listOfNumbers(4);
add.listOfNumbers(5);

private int forPrint;

// Vi skapar integens i som börjar med värdet 0. Detta är vår counter
// Så länge villkoret listOfNumbers(i) != 3 så körs loopen
// Varje varv loopen körs så ökar countern med 1
for (int i = 0; listOfNumbers(i) != 3; ++i) { 
   forPrint = i;
}

System.Out.println(forPrint); // Siffran 3 kommer att skrivas ut i terminalen



(konceptet while-loop är samma för både programspråket C och Java)
Wikipediaartikeln

Unified Modelling Language (UML)

UML-diagram
Ett UML-schema beskriver relationen mellan klasser

Unified Modeling Language (UML) är ett objektorienterat sätt att modelera system som beskriver hur olika klasser hör ihop. Ett klassdiagram (som du ser till höger) är en beskrivning över en klass, vad klassen heter, vilka attribut/variabler klassen har och dess metoder. Det beskriver också vilken access varje attribut och metod har genom ett "prefix" (tecken) som skrivs innan attributet/metoden. Det beskriver dessutom vilket indata varje metod har, samt om metoden returnerar något data.

Access klassdiagram
Prefix Access Explanation
+ public Synlig för klassen, paketet, subklasser och värld.
- private Synlig enbart i klassen
# protected Synlig för klassen, paketet och subklasser.
understruken static Ett static attribut behöver inte instanseras för att användas.
italic abstract Klassen kan inte instanseras och innehåller metoder som måste implementeras.

Ett fullt UML-schema beskriver vilka relationer klasserna har till varandra och om en klass ärver eller implementerar en annan klass. Schemat beskriver även om en klass använder, äger eller "har" en annan klass.

UML-arv. Animal är superklass som subklasserna Cat och Dog ärver ifrån







Wikipediaartikeln

Länkar

Kursplan