Chapter 4
Objekt-orienteret programmering i Java, del 2

Kurt Nørmark ©
Department of Computer Science, Aalborg University, Denmark


September 2001


Abstract
Previous lecture Next lecture
Index References Contents
Denne lektion fortsætter hvor den forrige slap. Vi studerer information hiding i Java, pakkebegrebet, værktøj i JDK programmeringsomgivelsen, klassevariable og metoder. Vi slutter af med at se på programbeskrivelse kontra programudførelse.


Pakker, import og class path

Pakke-begrebet i Java
Slide Note Contents Index
References Speak
Hvis man har mange klasser er det en praktisk nødvendighed at kunne gruppere disse på en hierarkisk måde. Det er netop det man kan med Java's pakkebegreb.

The concept pakke: En pakke i Java er en mængde af logisk sammenhørende klasserPakkebegrebet tillader os at gruppere klasserne i logisk sammenhørende delmængder

  • Karakteristika ved pakkebegrebet i Java

    • Pakker er organiseret i et hierarki

      • Java benytter operativsystemets hierarkiske filsystem til at organisere pakker

      • En pakke er repræsenteret som et katalog (et 'directory')

    • Hver pakke udgør et navnerum:

      • To klasser med samme navn i hvert sit navnerum kan undgå at komme i konflikt med hinanden

    • 'Information hiding' i Java afhænger af pakkebegrebet

      • Klasser i samme pakke har 'lettere ved' at se hinandens egenskaber end klasser i forskellige pakker

Reference

En pakke i Java svarer til en klynge i OOA&D

Anbefalet organisering af klasser
Slide Note Contents Index
References Speak
Vi beskriver her en anbefalet og relativ simpel strukturering af klasser i filer og pakker. Virkeligheden er dog mere kompliceret end dette. Vi vender tilbage til dette på den efterfølgende side

  • En fil med Java kildeprogram bør kun indeholde én klasse

    • Navnet på filen skal være det samme som klassen

    • Filens extension skal være 'java'

    • Klassens pakke angives øverst i filen med
        package pakkeNavn;

    • Filen placeres i et katalog, der har et tilsvarende navn som pakken

Pakker og klasser navngives med et punktum imellem niveauerne. Eksempelvis refererer 'P.Q.C' til klassen C i pakken Q, som er indeholdt i pakken P. I filsystemet indeholder kataloget P kataloget Q, som igen indeholder filen C.java. På et Unix system adresserer vi klassen som P/Q/C.java (på en PC som P\Q\C.java)

Alternative organiseringer af klasser
Slide Note Contents Index
References Speak
Det er undertiden praktisk at have mere end én klasse pr. fil. Dette er specielt tilfældet hvis man har mange små 'hjælpe klasser'. Det kan også være praktisk at overveje en katalogvis separering af Java kilde filer fra Java byte kode filer.

  • Mere end én klasse pr. fil

    • Nyttigt hvis man har mange små klasser.

    • Regler:

      • Der må kun være én offentlig klasse pr. fil

      • Øvrige klasser skal være uden 'visibility modifier': Kun brugbare i den aktuelle pakke

      • Navnet på filen skal være det samme som navnet på den offentlige klasse

  • Kildefiler og byte code filer i hvert sit katalog

    • Mere orden og overskuelighed i katalogerne

    • I nogle situationer ønsker man ikke at afsløre kilde programmet for uvedkommende

    • Brug -d option på javac kommandoen til at angive det sted i filsystemet, hvor byte code filer skal skrives

Reference

Tilgang til klasser i andre pakker
Slide Note Contents Index
References Speak
Klasser i samme pakke kan umiddelbart tilgå hinanden. Det betyder f.eks. at en klasse umiddelbart kan lave instanser af en anden klasse i samme pakke. De to klasser kan umiddelbart 'bruge hinanden'. Anderledes forholder det sig for klasser i forskellige pakker

  • En klasse C i en anden pakke P tilgås via det hierarkiske navn
      P.C

  • En klasse C i en pakke P i en pakke Q tilgås tilsvarende
      Q.P.C

  • For at hindre udbredt brug af pakke-dot-navne på klasser understøtter Java import af klasser og pakker

    • Eneste formål af import er at stille klassenavne til rådighed uden brug af pakke dot-notation

    • Import P.C

      • Klassen C i pakken P kan benyttes umiddelbart (uden brug af navnet P.C)

    • Import P.*

      • Alle klasser i pakken P kan benyttes umiddelbart (uden foranstillet P.-)

Hvis to klasser af samme navn importeres fra forskellige pakker skal man bruge pakke kvalificerede klasse navne for at benytte disse klasser

Pakken java.lang er altid importeret i et Java program

At java.lang altid er importeret betyder, at klasserne i denne pakke altid er umiddelbart til rådighed for java programmøren

Reference

Eksempel på klasser i pakker
Slide Note Contents Index
References Speak
Her viser vi tre klasser i to pakker som en konkret illustration af indholdet på de forrige sider

En klasse ClassA som benytter ClassB og ClassC fra pakken enPakke

Program: En klasse Class A som benytter ClassB og ClassC fra pakken enPakke. Bemærk ClassB importeres, men at ClassC ikke importeres. Dette vil være ganske underligt i et virkeligt og praktisk program. Her har vi gjort denne forskel for at illustrere forskellen mellem en importeret klasse (ClassB) og en ikke importeret klassse (ClassC).
import enPakke.ClassB;
class ClassA {

  ClassB v;
  enPakke.ClassC w;

  public ClassA(){
    v = new ClassB(5);
    w = new enPakke.ClassC(6);
  }

  public String toString(){
    return "En instans af ClassA";
  }

  public static void main (String[] args){
    ClassA a = new ClassA();
    System.out.println(a);
  }
}

  

Program: En klasse ClassB i pakken enPakke. ClassB skal være public i sin pakke for at kunne anvendes fra en anden pakke.
package enPakke;
public class ClassB {   // skal være public for at kunne ses fra A.

  int i;

  public ClassB (int i){
    this.i = i;
  }

  public String toString(){
    return "En instans af B med værdien " + i;
  }

}

Program: En klasse ClassC ganske tilsvarende til ClassB.
package enPakke;
public class ClassC {   // skal være public for at kunne ses fra A.

  int i;

  public ClassC (int i){
    this.i = i;
  }

  public String toString(){
    return "En instans af C med værdien " + i;
  }

}

Hvordan lokaliseres en klasse?
Slide Note Contents Index
References Speak
Klasser benytter sig typisk af andre klasser. Problemstillingen, som vi her ser på, er hvordan compileren og fortolkeren lokaliserer de klasser, der er behov for. Vi ser specielt på en angivelse af den såkaldte class path. Vi vil her interessere os for de mere princielle forhold omkring lokalisering af klasser. For detaljer henvises til JDK dokumentationen, hvortil vi refererer nedenfor.

Oversætteren og fortolkeren har behov for at kunne lokalisere Java byte code filer og Java kilde filer

Hvilke steder i filsystemet skal oversætter og fortolker lede efter sådanne filer?

Behovet opstår f.eks. når vi i et program skal type checke et kald af en metode, som befinder sig i en klasse i en anden fil. Java værktøjet vil i dette tilfælde forsøge at finde den oversatte fil eller kilde filen, hvor klassen befinder sig.

The concept Class path: Class path definerer steder i filsystemet (pakker) hvor Java værktøjet leder efter klasser, som ikke er systemklasser og udvidelsesklasserSystemklasserne definerer selve java platformen; disse leveres med JDK omgivelsen. Udvidelsesklasserne (extensions) er pakker af udvidelser til Java platformen, som typisk befinder sig i et bestemt og fast katalog. Hvis alle java filer befinder sig i 'det nuværende katalog' er det ikke nødvendigt at bekymre sig om class path. Hver sti i class path peger på et katalog eller zip/jar fil, som repræsenterer en Java pakke.

Figure. Vi ser en skitse af et filsystem hvor classpath udpeger en mængde af 'punkter'. Disse punkter er de ydre pakker, som kan indeholde filer med klasser. Punkterne kan også indeholde andre pakker med filer og eller pakker. De markerede, lysegrønne områder er således de områder, der kan indeholde java class filer.

References

Classpath kan overføres som parameter (option) til oversætter og fortolker

Classpath kan også defineres som en operativsystem 'environment variabel', og evt indføres i en startop fil (såsom .login eller .cshrc)


Information hiding

Information hiding i forskellige objekt-orienterede sprog
Slide Note Contents Index
References Speak
Som allerede omtalt i den første lektion er kontrol af synlighed af variable og metoder et meget væsentligt element af objekt-orienteret programmering. Vi starter med at se på nogle generelle forhold om information hiding i objekt-orienterede programmeringssprog

Det grundliggende spørgsmål er hvad klienter af klassen kan se, og hvad der privat i klassen

  • Forskellige måder at understøtte 'information hiding' i objekt-orienterede programmeringssprog

    • Sproget har faste og uforanderlige regler for synlighed

      • Alt er synligt (Beta)

      • Alle instansvariable er private, alle metoder er synlige (Smalltalk)

    • Sproget overlader det til programmøren at bestemme synligheden

      • Der findes en 'export liste' i hver klasse der angiver de variable og metoder, som er synlige fra klientside (det oprindelige Eiffel)

      • Klassen kategoriserer variable og metoder i afdelinger, hvoraf nogle er synlige udaftil, og nogle er private (C++, Eiffel)

      • Hver variabel og metode angiver eksplicit i sin egenskabslister om den er synlig fra klienter eller ej (Java)

Det anbefales generelt at have private instansvariable og at gøre en delmængde af metoderne offentlige

Reference

Information hiding i Java
Slide Note Contents Index
References Speak
Vi vil nu se på hvordan Java understøtter information hiding. For fuldstændighedens skyld nævner vi også nogle synlighedsforhold, som først for alvor gør sig gældende når vi begynder at beskæftige os med nedarvning. I diskussionen på de følgende sider omtaler vi pakker (packages). En pakke er en samling af klasser, som hører logisk sammen (og som befinder sig i samme katalog i filsystemet). Vi ser på pakker senere i denne lektion.

  • Java benytter følgende 'modifiers' til definition af variable's og metoder's synlighed

    • private

      • Egenskaben er privat i denne klasse

      • Kan dog ses fra andre objekter af samme klasse

      • Synlig for sig selv

    • public

      • Egenskaben kan ses af alle klasser i alle pakker

      • Synlig for alle

    • package - angives uden modifier (default synlighed)

      • Egenskaben kan ses af alle klasser i samme pakke som denne klasse

      • Synlig for naboerne

    • protected

      • Egenskaben kan ses i klassen selv, i alle subklasser

      • ... og i alle klasser i samme pakke

      • Der er specialregler for subklasser i andre pakker

      • Synlig i familien

Java benytter såkaldte modifiers til angivelse af synlighed. Modifiers benyttes også til angivelse af andre egenskaber, såsom 'final' (konstant) og 'static'

Det virker sært at Java ikke understøtter en 'modifier' for package synlighed.

Protectede egenskaber er underligt urene i Java, idet denne form for synlighed både involverer pakke-synlighed og subklasse-synlighed. Specielt er det tricket at forstå hvorledes subklasser i fremmede pakker håndteres. Mere om dette i lektionen om nedarvning.

References

Information hiding i Konto
Slide Note Contents Index
References Speak

Program: Vi ser her anvendelsen af synligheds modifiers i klassen Konto. Som det ses har vi fulgt anbefalingen om at instansvariablene er private. Bemærk, at konsekvensen af dette er, at vi skal definere trivielle metoder til aflæsning af de relevante instansvariable. balance er en sådan metode
class Konto {
   private double rentesats;
   private String navn;
   private double saldo;

   public Konto(String ejer) {
      rentesats = 0.02;
      navn = ejer; 
      saldo = 0;
   }

   public double balance () {
      return saldo;
   }

   public void hæv (double beløb) {
      saldo = saldo - beløb;
   }

   public void indsæt (double beløb) {
      saldo = saldo + beløb;
   }         

   public void tilskrivRente() {
      saldo = saldo + saldo * rentesats;
   }

   public String toString() {
      return navn + "'s konto indeholder "
            + saldo + " kroner";
   }
} // End Konto

I nogle objekt-orienterede sprog vil man kunne gøre variablen 'saldo' offentlig som 'read only'

I sådanne sprog kan man ikke fra klientside se forskel på en variabel og kald af en parameterløs funktion

Mere om information hiding
Slide Note Contents Index
References Speak

  • Kan en privat variabel eller metode i ét objekt ses fra andre objekter i samme klasse?

    • Ja, i Java

  • Er det muligt at synliggøre navne til nogle klasser, men ikke til andre?

    • I Java kun hvis klasserne adskiller sig fra hinanden ved 'at tilhøre den aktuelle pakke' og 'en anden pakke'

  • Synlighed af klasser i Java

    • En klasse i Java kan angives som public i betydningen at den kan ses fra alle andre klasser i alle pakker

    • En klasse uden 'access modifier' kan kun bruges fra klasser i samme pakke som klassen selv

    • Protectede og private klasser understøttes ikke på topniveau i Java

Opgave: Klassen Rectangle
Slide Note Contents Index
References Speak
Her introducerer vi én af denne lektions opgaver

Exercise 4.1. Programmering af klassen RectangleDenne opgave går ud på at programmere en klasse Rectangle. (En sådan klasse findes i forvejen i Java klassebiblioteket, men dette ignorerer vi i denne opgave). Et rektangel er et velkendt geometrisk objekt med en bestemt placering i et todimensionelt koordinatsystem. I denne opgave vil vi afgrænse os til at arbejde med rektangler, hvis sider er parallelle med akserne i koordinatsystemet. Antag også at vi arbejder med heltallige koordinater og dimensioner.

Start med at beslutte hvordan I vil repræsentere et rektangel. Datarepræsentationen skal være skjult for klienter af rektanglet.

Implementer følgende konstruktorer og metoder i Rectangle:

    En konstruktor som opretter et rektangel ud fra to hjørnepunkter: øverste venstre og nederste højre. En konstruktor som opretter et rektangel ud fra øverste venstre hjørne samt en bredde og en højde af rektanglet. En konstruktor som opretter et rektangel ud fra fire heltal: x og y koordinaterne af øverste venstre samt nederte højre hjørne Metoder width og height som returnerer bredde og højde af rektanglet En metode corners som returnerer et array af de fire hjørnepunkter af rektanglet En metode move der flytter rektanglet. Flytningen skal være relativ til den nuværende position. En metode overlappingRectangle der returnerer overlappet (i sig selv et rektangel) mellem to rektangler (se herunder). Metoden toString som udskriver en tekstuel og informativ streng om rektanglet
Under løsningen af denne opgave bedes I benytte klassen java.awt.Point som beskriver et punkt i den todimensionelle plan.

Det vanskeligste aspekt af klassen Rectangle er metoden overlappingRectangle. Det kan være en god hjælp at bruge klassen Interval (udviklet til formålet) hvori der findes en metode, der returnerer overlappet mellem to intervaller.

Dokumenter endvidere klassens konstruktorer og metoder, og producer HTML dokumentation ved brug af værktøjet javadoc.


Værktøj

Værktøj i Javaprogrammerings omgivelsen
Slide Note Contents Index
References Speak
Værktøj i en programmeringsomgivelse er programmer, som arbejder på andre programmer. Et typisk værtøj er en compiler eller en editor

The concept programmeringsomgivelse: En programmeringsomgivelse er en mere eller mindre integreret mængde af programudviklingsværktøj, som understøtter programudviklingsprocessenOrdet programmeringsomgivelse bruges om samlingen af værktøj, som understøtter 'det at udvikle programmer'. I nogle systemer er samlingen af værktøj integreret tæt i hinanden (måske så tæt, at man slet ikke fornemmer eksistensen af individuelt værktøj). Dette var situation i Turbo Pascal, som de fleste kender. I andre systemer er værktøjerne meget isolerede og separate; Programmøren er her bevidst om, at omgivelsen består af flere stykker værktøj
The concept Java Development Kit: Java Development Kit (JDK) indeholder et antal basale værktøjer, som gør det muligt at oversætte og udføre Java programmerJava development Kit (JDK) er en samling af værktøj, som kun er løst integreret. De vigtigste og mest centrale værktøjer er compileren og fortolkeren; men der findes en del andre værktøjer, som understøtter Java programmøren

  • Vigtige værktøjer i JDK

    • javac

      • Java compileren

      • Oversætter Java kildeprogram til Java byte code

      • javac [options] filename.java

    • java

      • Java fortolkeren

      • Udfører java byte code pr. fortolkning

      • java [options] classname

References

Værktøj i Javaprogrammerings omgivelsen
Slide Note Contents Index
References Speak
Værktøj i en programmeringsomgivelse er programmer, som arbejder på andre programmer. Et typisk værtøj er en compiler eller en editor

  • Flere Vigtige værktøjer i JDK

    • javadoc

      • Producerer dokumentation af udvalgte dele af en Java klasse

      • Dokumentationen kan læses direkte via en WWW browser

      • javadoc [options] package

      • javadoc [options] filename.java

JDK er en simpel og minimal programmeringsomgivelse for Java.

Der findes flere andre, mere avancerede omgivelser til Java.

JDK kan gøres mere tilgængelig og letanvendelig hvis man definerer en fleksibel grænseflade fra den teksteditor, man anvender til editering af kildefiler (typisk Emacs).

References

Et eksempel på brug af javadoc
Slide Note Contents Index
References Speak
Vi ser her hvordan grænsefladen af klassen Konto, som vi har studeret adskillige gange indtil nu, kan dokumenteres ved brug af JavaDoc værktøjet.

Program: Man kan køre javadoc på dette program med javadoc -d docs Konto.java. Dette skaber grænseflade dokumentation af Konto i underkataloget docs.
/** En klasse som repræsenterer en simpel bankkonto */
public class Konto {
   private static final double RenteSats = 0.02; 
   private String navn;
   private double saldo;

   /** Initialiserer konto med ejer nyt_navn og saldo 0 */
   public Konto(String nyt_navn) {
      navn = nyt_navn; 
      saldo = 0;
   }

   /** Træk beløb på konto
       @see Konto#indsæt(double) tilsvarende metode indsæt */
   public void hæv ( double beløb ) {
      saldo = saldo - beløb;
   }

   /** Indsæt beløb på konto 
       @see Konto#hæv(double) tilsvarende motode hæv */
   public void indsæt ( double beløb) {
      saldo = saldo + beløb;
   }         

   /** Overfør beløbet fra denne konto til kontoen fra */
   public void overførFra(double beløb, Konto fra) {
      fra.hæv(beløb);
      indsæt(beløb);
   } 

   /** Tilskriv rente til denne konto.
       Rentesatsen er en fast konstant i Konto klassen */
   public void tilskrivRente() {
      saldo = saldo + saldo * RenteSats;
   }

   /** Returner en streng repræsentation af denne konto */
   public String toString() {
      return navn + "'s konto indeholder "
            + saldo + " kroner";
   }
} // Konto







Reference


Klasseegenskaber

Klassevariable og klassemetoder
Slide Note Contents Index
References Speak
Vi vil her studere et alternativ til instansvariable og (instans)metoder, som vi hidtil har set på, nemlig de såkaldte klassevariable og klassemetoder. På næste side ser vi på, hvorledes disse begreber understøttes i Java

The concept klassevariabel: En klassevariabel er en variabel, som er fælles for alle instanserne af en klasseVi har defineret en klassevariabel som en variabel, der er fælles for alle instanser af en klasse. Vi kunne, alternativt, definere en klassevariabel som en instansvariabel i klassen af metaobjektet (altså i metaklassen), jf. nedenstående snak om metaobjekter.
The concept klassemetode: En klassemetode er en metode, der opererer på klassen som et objekt.

  • Er klasser objekter?

    • Hvis ja: Vi siger at der eksisterer et metaobjekt , der repræsenterer klassen

    • Metaobjektet er et naturligt hjemsted for klassevariable

    • Java understøtter metaobjekter via klassen Class samt klasserne i pakken java.lang.reflect

Java skaber en instans c af klassen Class når en bestemt klasse loades. Objektet c repræsenterer således klassen's egenskaber på køretidspunktet.

Man kan spørge: Hvordan får jeg fat i det objekt, som repræsenterer en bestemt klasse. Svaret er: obj.getClass(). Metoden getClass er en af de få metoder i klassen Object (roden i klassehierarkiet). Hvis man kender navnet på klassen (fuldt navn incl. pakke) kan man finde det objekt, som repræsenterer klassen via den statiske metode forName(String) i klassen Class.

References

Statiske egenskaber af en klasse i Java
Slide Note Contents Index
References Speak
Statiske egenskaber, erklæret ved brug af nøgleordet static, kendes også fra C. Men det er vigtigt at forstå, at der er stor forskel på betydningen af static i C og Java. I Java er betydningen i grove træk at en egenskab er klassetilknyttet i modsætning til at være objekt-tilknyttet. I C er der flere forskellig betydninger. En statisk variabel eller funktion har et scope der er begrænset til den fil, hvori den er erklæret. Statiske lokale variable i en C funktion nedlægges ikke mellem kald af funktionen.

  • Variable markeret med 'static modifier' er klassevariable i Java

    • Disse variable er hævet over instanserne, og de er fælles for mængden af instanser

  • Metoder markeret med 'static modifier' er en form for klassemetoder i Java

    • Statiske metoder i Java kræver ikke en instans af klassen (et objekt) for at kunne aktiveres

    • Statiske metoder i en klasse kan ikke tilgå instansvariable

Eksempel. Metoden isDigit i klassen Character er et eksempel på en klassemetode i Java
 

Konstanter erklæres ofte for 'static' i Java

Overdreven brug af statiske egenskaber giver mindre objekt-orienterede programmer

Konstanter erklærers ofte for statiske i Java idet en mængde af objekter lige så godt kan deles om sådanne. Konstanter erklæres således for det meste som 'final static' i Java

References

Initialisering af klassevariable i Java
Slide Note Contents Index
References Speak
Kontruktorerne har til opgave at initialisere instansvariablene i Java. Men hvordan initialiseres klassevariablene i Java. Det er problemstillingen vi ser på her.

Static variable initialiseres enten i forbindelse med deres erklæring, eller i en særlig statisk initialiseringsblok i klassen

I langt de fleste situation kan statiske variabel initialiseres med en 'initializer' umiddelbart i forlængelse af definitionen:

    static Type obj = new Type(...)
I specielle tilfælde (hvor der kan opstå fejl der ønskes håndteret) kan denne løsning ikke anvendes. I sådanne situationer er static blocks nødvendige.

Syntax: Syntaksen af en static block, hvori statiske variable (klasse variable) kan initialiseres. Semantisk set udføres blokkens kommandoer kun én gang, nemlig når klassen 'loades'.

static{
  kommando-liste
}

Program: Et eksempel på en statisk initialiseringsblok. En klasse som viser et eksempel på brugen af en statisk initialiseringsblok. I blokken initialiseres to arrays som tabellægger sinus og cosinus i et interval. Vi forestiller os, at en sådan tabel kan være nyttig i Circle klassen, og ikke mindst hurtigere end beregning af sinus og cosinus via funktionskald. Eksemplet er taget fra bogen 'Java in A Nutshell', 2, edition, af David Flanagan, fra O'Reilly.
public class Circle {

  static private double sines[] = new double[1000]; 
  static private double cosines[] = new double[1000]; 

  // Pre calculation of sines and cosines:
  static {
    double deltaX = (Math.PI/2)/(1000-1);
    double x;
    int i; 
    for(i=0, x = 0.0; i < 1000; i++, x = x+deltaX){
      sines[i] = Math.sin(x);
      cosines[i] = Math.cos(x);
    }
  } //end static

  // Circle operations: Use sines[x] instaed of the static method Math.sin(x) 
  // and cosines[x] instead of the static method Math.cos(x).

  // ...
}  

Java understøtter også en instans initialiseringsblok.

Konstruktorer er dog tilstrækkelige i næsten alle initialiseringssituationer

Instans initialiseringsblokke er en sædvanlig blok af kommandoer, som kan placeres en vilkårlig sted i en klasse. I forbindelse med skabelse af objekter bliver sådanne blokke udført (i en ganske bestemt rækkefølge, på et ganske bestemt tidspunkt i forhold til konstruktoren: før klassens konstruktor, men efter udførelse af superklassen's konstruktor). Man kan placere vilkårligt program i sådanne blokke. Men lad vær'! Det vil ikke give gode programmer, og der er stor fare for, at en sådan programmeringsstil vil fjerne sig fra den objekt-orienterede stil vi går efter på dette kursus.

References


Udførelse

Programbeskrivelse kontra programudførelse
Slide Note Contents Index
References Speak
Det er meget vigtigt at holde programbeskrivelsen (klasserne) adskilt fra programudførelsen (objekter, med indbyrdes referencer). I nogle sprog er klasser også objekter, som kan manipuleres af et sæt af operationer. Disse kaldes for metaobjekter. Smalltalk og CLOS er eksempler på sådanne sprog. Når klasser også er objekter, kan man spørge sig selv, hvilke klasser klasse-objekterne er instanser af? Normalt kalder man klasser, hvis instanser repræsenterer klasser, for metaklasser. Operationerne i disse metaklasser tillader, at man undersøger og påvirker aspekter af programmet selv. Med en passende organisering af programmeringsomgivelsen befordrer metaobjekterne at et program kan tilgå information om sig selv. Dette kaldes undertiden for refleksion. Dette er imidlertid et videregående emne, som ikke berøres yderligere på dette kursus

The concept programbeskrivelse: Statisk programbeskrivelse som det fremgår af programteksten
    Klasser med instansvariable og metoder
At programbeskrivelsen omtales som statisk betyder, at det er relativ uforanderlig. Dette skal naturligvis ses i forhold til programudførelsen. Programbeskrivelsen er dog foranderlig i den forstand at programmøren via værktøj i programmeringsomgivelsen kan ændre den
The concept programudførelse: Dynamisk programudførelse som det forekommer i maskinen, når programmet kører
    Objekter med instansvariable, som indeholder værdier og referencer til objekter
Programudførelsen's elementer ændrer sig hele tiden, som en funktion af tiden.

Objekter og referencer udgør et netværk, som udvikler sig i takt med at programudførelsen skrider frem.

På ethvert tidspunkt er netop et objekt 'det nuværende objekt'

Det nuværende objekt kan i et Java program refereres via nøgleordet this

Objekt-interaktion
Slide Note Contents Index
References Speak
Objekter interagerer som bekendt med hinanden ved at sende beskeder. Vi vil her se på et scenario som illustrerer, hvordan objekt-interaktion kan udvikle sig mellem 'et netværk' af objekter. Vi fokuserer både på objekterne under udførelsen, og på de bagved liggende klasser i programbeskrivelsen

Objekter interagerer med hinanden ved at sende beskeder

En besked til et objekt forårsager aktivering af en metode i objektets klasse

Image series: Et scenarie hvor et kundeobjekt indsætter 500 kroner i banken.Et scenarie hvor et kundeobjekt indsætter 500 kroner i banken. Vi viser objekt-interaktionen som følger af, at en kunde sætter 500 kroner i banken. Det nuværende objekt er vist med rød farve. Vi skitserer endvidere programmet i de klasser i bankprogrammet som er involveret i interaktionen.

Image no. 1. En kunde sender beskeden indsæt til sin bank. Via parametre angives, at der skal indsættes 500 kroner på konto 'K1234'
 

Image no. 2. Bank objektet finder kontoen frem ved at sende en besked til et objekt, som repræsenterer samlingen af bankkonti i banken
 

Image no. 3. Objektet, som repræsenterer samlingen af bankkonti finder kontoen i en database, og metoden findKonto returnerer kontoen til banken
 

Image no. 4. Banken sender beskeden indsæt til den fremfundne konto. Som parameter angives beløbet
 

Image no. 5. I kontoen aktiveres metoden indsæt, som opdaterer kontoen's saldo
 

Image no. 6. Banken er igen det nuværende objekt. Banken sender beskeden gemKonto til samlingen af bankkonti. Kontoen sendes med som parameter.
 

Image no. 7. Vi ser metoden gemKonto i klassen KontoSamling, som blev aktiveret af banken. Hermed slutter scenariet.
 

Det er ofte vanskeligt at afgøre i hvilket objekt man skal placere en given funktionalitet

Eksempel. Skal beskeden gemKonto sendes til enKontoSamling med enKonto som parameter eller
Skal beskeden gemKonto sendes til enKonto med enKontoSamling som parameter
Vi stødte på denne problemstilling i scenariet ovenfor. Her valgte vi at lade kontosamlingen være ansvarlig for fremskaffelse og lagring af konti. Alternativt kunne vi flytte ansvaret for lagring af en konto til Kontoklasse. I dette tilfælde er det naturligt at 'find' og 'gem' er metoder i samme klasse
 

Placering af funktionalitet på klasser beror på den valgte ansvarsfordeling mellem klasserne

Dette er et emne som tages op i designfasen af udviklingsprocessen

Vi henviser til hosstående reference for en yderligere diskussion af ansvarsfordeling

Reference

Hvordan starter udførelsen af et objekt-orienteret program?
Slide Note Contents Index
References Speak

  • Forskellige muligheder

    • Fortolkeren instantierer en særlig udnævnt klasse, hvori en særlig udnævnt metode starter programudførelsen

    • Udførelsen tager udgangspunkt i en særligt udnævnt statisk metode, som jo ikke kræver et objekt for at kunne starte

I java kan man starte et program via den statiske metode main i en klasse

'Multidotning' i Java
Slide Note Contents Index
References Speak

Java tillader udtryk på formen x.y.z.v.w

Hvordan hænger et sådan udtryk sammen, og hvad betyder det?

Symbolerne x, y, z osv. kan være instansvariable eller beskeder (metode aktiveringer). I sidstnævnte tilfælde skal der i Java også være parenteser med evt. aktuelle parametre

  • Dot syntaksen er notation for object member reference operatoren

  • Object member reference operatoren er venstre associativ

    • x.y.z.v.w hænger syntaktisk sammen som (((x.y).z).v).w

      • Vi tager udgangspunkt i x

      • På x refererer vi til y, som skal returnere et objekt (lad os sige o1)

      • På o1 referer vi til z, som skal returnere et objekt (lad os sige o2)

      • På o2 referer vi til v, som skal returnere et objekt (lad os sige o3)

      • På o3 referer vi til 3

Når vi siger at et udtryk 'syntaktisk hænger sammen' på en bestemt måde kunne vi også tale om parsning af udtrykket. Parsning betyder at uddrage struktur af en flad præsentation, i dette tilfælde en tekststreng, som repræsenterer udtrykket

Mere 'multidotning' i Java
Slide Note Contents Index
References Speak

Multidot notation

Alternativ programmering

x.y.z.v.w

v1 = x.y;
v2 = v1.z;
v3 = v2.v;
v4 = v3.w;

Program: Et Java program som illustrerer multidotning i kombination med metode aktivering. Beskeden anotherC(5) sendes til obj (et C objekt), som returnerer et nyt C objekt, der sendes beskeden anotherC(6), der returnerer et nyt C objekt, der sendes beskeden anotherC(7), der returnerer et nyt C objekt, hvis reference assignes til res. Programmet udskriver tallet 28
public class MultidotDemo1{

  static C obj = new C(10);
  static C res;

  public static void main(String[] args){

    res = obj.anotherC(5).anotherC(6).anotherC(7);
    System.out.println(res);

  }

}


class C{

 int state;

 public C(int i){
   state = i;
 }

 public C anotherC(int i){
   return(new C(this.state + i));
 }

 public String toString(){
   return(Integer.toString(state));
 }

}

Program: Et tilsvarende Java program som undgår brug af multidotning. Mellemresultaterne lagres i variablene res1 og res2
public class MultidotDemo2{

  static C obj = new C(10);
  static C res, res1, res2;

  public static void main(String[] args){

    // res = obj.anotherC(5).anotherC(6).anotherC(7);

    res1 = obj.anotherC(5);
    res2 = res1.anotherC(6);
    res = res2.anotherC(7);

    System.out.println(res);

  }

}


class C{

 int state;

 public C(int i){
   state = i;
 }

 public C anotherC(int i){
   return(new C(this.state + i));
 }

 public String toString(){
   return(Integer.toString(state));
 }

}


Indlejring af klasser i hinanden

Oversigt over indlejring af klasser
Slide Note Contents Index
References Speak
Vi starter med en oversigt over mulighederne for at indlejre klasser i hinanden. På de følgende sider vil vi se nærmere på nogle detaljer omkring dette. Hvis man ønsker at studere dette emne nærmere kan jeg anbefale et kapitel af bogen 'Java in a nutshell', jf. referencen nederst fra denne side.

Klasser i Java kan på forskellig måde indlejres i andre klasser

Det er muligt at definere en klasse et vilkårligt sted i kroppen af en metode

Observationen om, at det er muligt at definere en klasse i kroppen af en metode er interessant set på baggrund af, at metoder ikke kan indlejres i hinanden på samme måde som vi f.eks. i Pascal kan have procedurer lokalt i procedurer.

  • Indlejrede klasser

    • Indre statiske klasser

      • Anvendes når en klasse logisk hører hjemme i en anden klasse.

    • Indre klasser

      • Anvendes når et objekt ønskes at være en del af et andet objekt.

    • Lokale klasser

      • Anvendes når der kun er behov for en indre klasse i et ganske bestemt afgrænset del af programmet.

    • Anonyme klasser

      • Anvendes typisk når der kun er brug for én instans af en lokal klasse.

Hvad vi her kalder indre statiske klasser omtales i The Java Tutorial som 'nested classes'.

References

Indre statiske klasser
Slide Note Contents Index
References Speak

Indre statiske klasser er hovedsagelig udtryk for en indlejret syntaktisk organisering af klasser

En indre statisk klasse har fuld adgang til statiske, private og offentlige egenskaber af de omkringliggende klasser

Statisk indlejring af klasser har ingen konsekvens for instansernes indlejring i hinanden

Observationen nummer to afspejler helt normal principper for blokstruktur: En lokal definition kan se og anvende alle egenskaber fra mere globale definitioner. Sådan er det også når vi indlejrer procedurer i hinanden.

Ligesom det er muligt statisk at indlejere klasser i hinanden, kan vi også indlejre interfaces statisk i en klasse. Interfaces hører vi mere om i en senere lektion

Eksempel. Klassen Spillekort kan indlejres statisk i klassen KortSpil. Dermed understreger vi samhørigheden mellem kort begrebet og et helt spil kort samtidig med at vi accepterer at enkeltkort kan eksistere uafhængigt af helhedsobjektet.
 

Program: En skitse af den statiske indlejring af klassen Spillekort i KortSpil.
public class KortSpil{

  static public class Spillekort{
    // Konstanter, instansvariable
    // konstruktorer og metoder.  
  }
  
  public Spillekort[] bunke = new Spillekort[52];

  // KortSpil konstruktorer og metoder.

}

Exercise 4.2. Klasserne Spillekort og KortSpilI forrige lektion var der en opgave om Spillekort, hvor klassen Spillekort repræsenterer et enkelt kort i et kortspil.

Da nogen måske ikke nåede at programmere Spillekort klassen sidste gang, er det en mulighed at løse opgaven ved øvelserne idag.

I min løsning har jeg implementeret en klasse KortSpil, som repræsenterer de 52 kort i spil kort (uden jokere). Vi har ovenfor anbefalet at indlejere Spillekort statisk i KortSpil. Afprøv denne løsning konkret, og demonstrer ved et eksempel, at der statig er adgang til SpilleKort (uden at gå igennem et KortSpil objekt) selv om den er indlejret i KortSpil.

Indlejr en klasse C1 statisk i en anden klasse C2 hvis C1 begrebet logisk set er et lokalt begreb til C2 begrebet

Husk i denne sammenhæng på at C1 objekter ikke bliver del-objekter af C1 objekter.

Reference

Indre klasser
Slide Note Contents Index
References Speak
Vi ser her på indre, ikke-statiske klasser. Overfladisk er forskellen blot, at den indre klasse ikke angiver 'static' foran klassedefinitionen. Men som vi vil se er forskellen på semantikken meget stor og væsentlig

En instans af en indre klasse er et delobjekt af en instans af en ydre klasse

Instansen af den indre klasse har fuld adgang til offentlige og private instans egenskaber af det/de omkringliggende objekter

Figure. En klasse Outer med en indre klasse Inner. Programmet vises herunder.

Program: Klassen Outer med den indre klasse Inner. Når vi laver en instans af Outer vil konstruktoren instantiere Inner. Ligeledes vil 'fabrikations metoden' makeInner lave en instans af Inner, som returneres til en klient af Outer. Dette vil betyde at en klient af Outer har en reference til et Inner objekt, som er en del af det Outerobjekt, hvorfra det blev lavet. Læg mærke til at Inner er en privat indre klasse. Det betyder i et og alt, at ingen klient af Outer selv kan instantiere Inner. Læg også mærke til at Inner refererer til Outer's private a instans variabel.
public class Outer {
  private int a = 7; 
  private Inner b;
 
  private  class Inner{
    private int x = 13;
    private int y = a;

    // fuld adgang til a og b fra Inner metoder
  } 

   public Outer(){
     b = new Inner(); 
   }  

   public Inner makeInner(){
     return new Inner();
   }
}

Reference

Variationer over eksemplet
Slide Note Contents Index
References Speak
Inspireret af eksempelt på forrige side ser vi nu på en række variationer. Man kan måske sige at eksemplet udarter lidt. Dog kan man ved at studere detaljerne få styrket sin forståelse af Java's muligheder angående indre klasser.

En instans af en indre klasse kan returneres fra en metode i den ydre klasse

Program: Klassen Outer med en offentlig indre klasse Inner.
public class Outer {
  private String outerId = "outer";
  private int a = 5;
  private Inner i;
  
  public  class Inner{
    private int x = a;
    private String innerId = "inner";

    public String toString(){
      return innerId + " " + outerId;
    }

    // fuld adgang til a og outerId fra Inner metoder
  }

  public Outer(){
    i = new Inner();
  }

  public Inner makeInner(){
    return new Inner();
  }
}
    
    

Program: En klient af Outer. Vi ser at et indre objekt kan returneres fra det ydre objekt via metoden makeInner. Det indre objekt holder fast i det ydre objekt, hvilket afsløres af udskriften 'inner outer'.
class Application {

  public static void main(String[] args){
    Outer o = new Outer();
    Outer.Inner i = o.makeInner();
    o = null;
    System.out.println(i);  // bruger toString()
  }

}


Program: Klassen Outer med en privat indre klasse Inner.
public class Outer {
  private String outerId = "outer";
  private int a = 5;
  private Inner i;
  
  private class Inner{
    private int x = a;
    private String innerId = "inner";

    public String toString(){
      return innerId + " " + outerId;
    }

    // fuld adgang til a og outerId fra Inner metoder
  }

  public Outer(){
    i = new Inner();
  }

  public Inner makeInner(){
    return new Inner();
  }
}
    
    

Program: En klient af Outer. Vi ser igen at et indre objekt kan returneres fra det ydre objekt via metoden makeInner. I klassen Application har vi imidlertid intet kendskab til klassen Inner, i det den er private i Outer. Derfor bliver vi nødt til at erklære i af den generelle klasse Object. På trods af dette får vi samme udskrift som i ovenstående variation: 'inner outer'. Vi vil først forstå dette i detaljer når vi har studeret nedarvning og dynamisk binding.
class Application {

  public static void main(String[] args){
    Outer o = new Outer();
    Object i = o.makeInner();
    o = null;
    System.out.println(i);  // bruger toString()
  }

}


Program: Klassen Outer med en offentlig indre klasse Inner.
public class Outer {
  private String outerId = "outer";
  private int a = 5;
  private Inner i;
  
  public class Inner{
    private int x = a;
    private String innerId = "inner";

    public String toString(){
      return innerId + " " + outerId;
    }

    // fuld adgang til a og outerId fra Inner metoder
  }

  public Outer(){
    i = new Inner();
  }

  public Inner makeInner(){
    return new Inner();
  }
}
    
    

Program: En klient af Outer som instantierer Inner i et Outer objekt. I dette eksempel laves Inner objektet uden om fabrikations metoden i Outer. Da Inner klassen er public kan vi instantiere Inner. Læg mærke til syntaksen for dette, og i særdeleshed o objektets rolle i instantieringen. Dette understreger at i skabes i o.
class Application {

  public static void main(String[] args){
    Outer o = new Outer();
    Outer.Inner i = o.new Inner();
    o = null;
    System.out.println(i);  // bruger toString()
  }

}


Lokale og anonyme klasser
Slide Note Contents Index
References Speak
Vi slutter af med at give et eksempel på en klasse som er lokal i en metode.

Det er muligt at definere en lokal klasse på ethvert sted i en blok, herunder i metoder og konstruktorer

En lokal klasse er som en indre klasse, der er placeret endnu mere specifikt

En anonym klasse er en klasse uden navn, som instantieres umiddelbart

Program: Klassen Outer med en lokal klasse Local i metoden method. Eksemplet er helt igennem kunstigt. Det er svært at forestille en situation, hvor noget lignende vil være nyttigt i praksis. Når vi senere får introduceret interfaces vil det dog undertiden være nyttigt at lave lokale klasser som instantieres og returneres til omverdenen. En sådan instans kan manipuleres via et interface. Dette program udskriver tallet 45. Lad os forklare hvad der sker i programmet. Hovedprogrammet main kalder den statiske metode method med 5 som parameter. method laver en instans af den lokale klasse. Konstruktoren Local initialiserer instVar til par + loc = 5 + 10 = 15. Bemærk at Local har tilgang til omkringliggende lokale variable og parametre i method. (Disse skal dog af implementationstekniske årsager være erklæret final - altså uforanderlige når først assignet). Metoden methodLocal anvendt på instansen af Local returnerer nu 3*InstVar = 3*15 = 45. method returnerer og instansen af Local forsvinder.
class Outer {

  public static void method (final int par){

    final int loc = 2*par;

    class Local {
      int instVar;

      public Local (){
        instVar = par + loc;
      }

      public int methodLocal () {
        return 3 * instVar;
      }
    } // Local

    Local locInst = new Local();

    System.out.println(locInst.methodLocal());
  }

  public static void main(String[] args){
    method(5);
  }

}
    
    

Reference


Collected references
Contents Index
Creating and using packages
The reference above goes to a Java Tutorial pageThe references above goes to material on the Internet
Dokumentation af javac
The reference from above goes to Java API pageThe references above goes to material on the Internet
Pakken java.lang
The reference from above goes to Java API pageThe references above goes to material on the Internet
How classes are found (detailed rules)
The reference from above goes to Java API pageThe references above goes to material on the Internet
Setting the class path (Solaris)
The reference from above goes to Java API pageThe references above goes to material on the Internet
Om opsætning af classpath (Lokal Java FAQ)
The references above goes to material on the Internet
Information hiding
The reference above goes to a lecture note pageThe reference above points to an earlier page in the lecture notes
Protectede egenskaber
The reference above goes to a lecture note pageThe reference above points to an succeding page in the lecture notes
Java modifiers: Appendix F i Lewis and Loftus giver en god oversigt over Java modifiers
The reference above goes to paper material
Controlling access to members
The reference above goes to a Java Tutorial pageThe references above goes to material on the Internet
Dokumentation af java
The reference from above goes to Java API pageThe references above goes to material on the Internet
Oversigt over Java værktøj
The reference from above goes to Java API pageThe references above goes to material on the Internet
Java Development Environment for Emacs (JDE)
The references above goes to material on the Internet
Eksempel på output produceret af javadoc
The reference from above goes to Java API pageThe references above goes to material on the Internet
Dokumentation af javadoc
The reference from above goes to Java API pageThe references above goes to material on the Internet
Den resulterende dokumentation
The references above goes to material on the Internet
Pakken java.lang.reflect
The reference from above goes to Java API pageThe references above goes to material on the Internet
Klassen Class i pakken java.lang
The reference from above goes to Java API pageThe references above goes to material on the Internet
Metoden isDigit i klassen Character
The reference from above goes to Java API pageThe references above goes to material on the Internet
Tidligere eksempel på klasevariable
The reference above goes to a lecture note pageThe reference above points to an earlier page in the lecture notes
Understanding Instance and Class Members
The reference above goes to a Java Tutorial pageThe references above goes to material on the Internet
Konstruktorer til initialisering af instansvariable
The reference above goes to a lecture note pageThe reference above points to an earlier page in the lecture notes
Ansvarsfordeling mellem klasser
The reference above goes to a lecture note pageThe reference above points to an succeding page in the lecture notes
Inner classes and other new Language features: Kapitel 5 af 'Java in a Nutshell' af David Flanagan fra O'Reilly
The reference above goes to paper material
Inner classes
The reference above goes to a Java Tutorial pageThe references above goes to material on the Internet
Implementing nested classes
The reference above goes to a Java Tutorial pageThe references above goes to material on the Internet
Interfaces
The reference above goes to a lecture note pageThe reference above points to an succeding page in the lecture notes
Eksempel på indre klasser: Linkable i LinkedList
The reference above goes to a lecture note pageThe reference above points to an succeding page in the lecture notes
Eksempel på anonym klasse: Adapters
The reference above goes to a lecture note pageThe reference above points to an succeding page in the lecture notes

 

Chapter 4: Objekt-orienteret programmering i Java, del 2
Course home     Author home     About producing this web     Previous lecture (top)     Next lecture (top)     Previous lecture (bund)     Next lecture (bund)     
Generated: March 31, 2008, 12:08:21