7 Lokale, objekt- og klassevariable

Indhold:



Forudsættes ikke i resten af bogen.

Forudsætter kapitel 4, Definition af klasser.



De variabler, vi er stødt på indtil nu, har enten været lokale variabler eller objektvariabler.

Objektvariabler hedder sådan, fordi de bliver oprettet for hvert objekt.


Der findes også variabler, der eksisterer "i klassen", uafhængigt af om der bliver oprettet objekter. Disse kaldes klassevariable og erklæres med nøgleordet static, og de kaldes også statiske variabler.


Herunder ses et eksempel på en klassevariabel og en klassemetode (antalBokse).

Klassevariabler og -metoder vises med understregning i UML-notationen (diagrammet til højre).


public class Boks4 
{
  private double længde;              // objektvariabel
  private double bredde;              // objektvariabel
  private double højde;               // objektvariabel
  private static int antalBokse;      // klassevariabel

  public Boks4(double lgd, double b, double h)
  {
    // lgd, b og h er lokale variabler
    længde = lgd;
    bredde = b;
    højde  = h;
    antalBokse = antalBokse + 1;
  }

  public static int læsAntalBokse()   // klassemetode
  {
    return antalBokse;
  }

  public double volumen()
  {
    // vol er en lokal variabel
    double vol;
    vol = længde*bredde*højde;
    return vol; 
  }
}


Variablen antalBokse er en klassevariabel, fordi den er erklæret med static-nøgleordet. Dette betyder, at variablen er tilknyttet klassen, og at alle Boks-objekter deler den samme variabel. Der vil eksistere én og kun én antalBokse-variabel, uanset om der oprettes 0, 1, 2 eller 100 Boks-objekter.


Variablerne bredde, højde og længde er objektvariabler, fordi hvert Boks-objekt har tilknyttet en af hver.


Og for fuldstændighedens skyld: Variablen vol er en lokal variabel, fordi den er erklæret lokalt i volumen-metoden og altså kun eksisterer, når volumen-metoden udføres. Ligeledes med lgd, b og h: De eksisterer kun i Boks' konstruktør.


En klassemetode er en metode, der er erklæret static. Den arbejder på klasseniveau (uafhængigt af om der er skabt nogen objekter) og kan derfor ikke anvende objektvariabler eller -metoder.


Vi kan afprøve Boks4 med:


public class BenytBoks4
{
  public static void main(String args[])
  {
    System.out.println("Antal bokse: "+ Boks4.læsAntalBokse());

    Boks4 boksen;
    boksen = new Boks4(2,5,10);

    System.out.println("Antal bokse: "+ Boks4.læsAntalBokse());

    Boks4 enAndenBoks, enTredjeBoks;
    enAndenBoks = new Boks4(5,5,10);
    enTredjeBoks = new Boks4(7,5,10);

    System.out.println("Antal bokse: "+ Boks4.læsAntalBokse());
  }
}

Antal bokse: 0
Antal bokse: 1
Antal bokse: 3


Inde fra objektet bruges statiske variabler og metoder ligesom de almindelige variabler og metoder. Det ses f.eks. i Boks' konstruktør:

    antalBokse = antalBokse + 1;


7.1 Eksempler i standardpakkerne

Du har allerede benyttet dig af et par statiske metoder og variabler.

7.1.1 Klassevariable

Der er mange klassevariabler i standardpakkerne. Af de oftest brugte kan nævnes



Som det ses, er klassevariabler nyttige til variabler, der er tilgængelige overalt. Det er det nærmeste man kommer globale variabler i Java, som det kendes fra andre programmeringssprog.

7.1.2 Klassemetoder

Af nyttige klassemetoder kan nævnes



7.2 Lokale variabler og parametre

Når en metode kaldes, opretter systemet en "omgivelse" for det metodekald. I denne omgivelse oprettes parametervariablerne og de lokale variabler.


En lokal variabel er kendt fra dens erklæring og ned til slutningen af den blok, der omslutter den
Dette kaldes variablens virkefelt

Den lidt indviklede formulering skyldes, at man kan lave variabler, der er lokale for en hvilken som helst blok - ikke kun en metode-krop. Man kan altså skrive noget som:


  ...
  int a=10;
  while (a>0)
  {
    double b; // b erklæres lokalt i while-blokken
    b=math.Random();
    ...
    System.out.println(b);
    a--;
  }
  System.out.println(a);
  System.out.println(b); // fejl: b eksisterer ikke, 
                         // fordi vi er uden for blokken.
...


Vi har desuden allerede set, at man i for-løkker kan erklære en variabel, der er lokal for løkkens krop:


  for (int i=0;i<10;i++) 
    System.out.print(i);

  System.out.print(i); // fejl: i eksisterer ikke uden for løkken.


7.2.1 Parametervariable

Parametervariablerne får tildelt en kopi af den værdi, de blev kaldt med, og opfører sig i øvrigt fuldstændigt som lokale variabler. Man kan f.eks. godt tildele dem nye værdier:


  ...
  // metode, der udskriver et bestemt antal stjerner på skærmen.
  public void udskrivStjerner(int antal)
  {
    while (antal>0)
    {
      System.out.print(”*”);
      antal=antal-1; // Det kan man godt
    }
    System.out.println();
  }

    ....
    int stj=10;
    udskrivStjerner(stj); // kald af udskrivStjerner
    // stj er stadig 10.
    ...


Dette mærker kalderen intet til, netop fordi kalderens værdi blev kopieret. Her skal man være opmærksom på forskellen mellem variabler af primitiv type og variabler af objekt-type. Fordi det sidste er referencer, peger parametervariablen på samme objekt som kalderen, når den bliver kopieret. Ved at ændre i objektet, som parametervariablen refererer til, kan man derfor ændre på kalderens objekt.


Derfor kan metoden herunder godt ændre på kalderens punkt-objekt:


  public void flyt(Point p, int dx, int dy)
  {
    p.x=p.x+dx;  // OK, vi ændrer på kalderens objekt
    p.y=p.y+dy;
  }

    ...
    Point p1=new Point();
    p1.x=10;p1.y=10;
    flyt(p1,10,10);
    // nu er p1 (20,20)
    ...


Men man kan stadig ikke ændre på kalderens reference. Dvs. p1's værdi:


  public void flyt(Point p, int dx, int dy)
  {
    // hmm... vi glemmer kalderens objekt, men det opdager han ikke
    p=new Point(p.x+dx,p.y+dy); 
  }

    ...
    Point p1=new Point();
    p1.x=10;p1.y=10;
    flyt(p1,10,10);
    // nu er p1 stadig (10,10)
    ...


En lokal variabel oprettes, når man går ind i blokken, hvor den er defineret, og nedlægges igen, når man går ud af blokken. Der bliver oprettet en ny variabel, hver gang programudførelsen går ind i blokken.

Hvis en metode bliver kaldt to gange, eksisterer der altså to versioner af den lokale variabel - én i hver deres omgivelse. Det behøver man som regel ikke at tænke på, men det er rart at have vished for at en anden ikke bare kan ændre ens lokale variabler.

7.2.2 Rekursion

Rekursion er en teknik, der netop udnytter, at der bliver oprettet en ny omgivelse med nye lokale variabler, hver gang en metode kaldes. En rekursiv metode er en metode, der kalder sig selv. F.eks.:


  void tælNed(int tæller)
  {
    System.out.print(”(”+tæller+” ”);
    if (tæller>=0) tælNed(tæller-1); // tælNed kalder sig selv !!
    System.out.print(” ”+tæller+”)”);
  }


Hvis man kalder tælNed(4), får man udskrevet følgende:


”(4(3 (2 (1 (0  0) 1) 2) 3) 4)”


Fidusen er, at parameteren tæller eksisterer én gang for hver gang, tælNed() kalder sig selv. Så når tælNed() vender tilbage til kalderen, som også er tælNed(), er tællers værdi bevaret som før kaldet.

Visse problemstillinger kan løses meget elegant med rekursion, men vi vil ikke her komme yderligere ind på emnet.


7.3 Test dig selv (fjernet)

Dette afsnit findes i den trykte bog


7.4 Resumé (fjernet)

Dette afsnit findes i den trykte bog



Jacob Nordfalk - Objektorienteret programmering i Java - http://javabog.dk