8.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.

8.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.

8.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.