Variablen

Wie Programme mit Daten umgehen – Variablen sind der wohl grundlegendste Baustein eines Computerprogramms.

MATERIALIEN

 

Jedes Programm besteht einerseits aus Arbeitsschritten, die dem Computer vorgeben, was er zu tun hat, und andererseits aus Daten, die zu verarbeiten sind, den Variablen.

A) Variablen als Bausteine

Variable

Erstellt von Seraina Hohl

Variablen dienen dazu, während der Laufzeit des Programms Werte zwischenzuspeichern. Eine Variable steht somit für einen (benannten) Platz im Arbeitsspeicher.

Analogie

Eine Variable kann mit einer Kiste verglichen werden:

Typ = Form und Grösse der Kiste;
Name = Aufschrift der Kiste;
Wert = Inhalt der Kiste.

Weil sich ohne Variablen kein Computerprogramm schreiben lässt (jedenfalls keines, das einen Algorithmus umsetzt), muss man sich die drei Aspekte dieses grundlegenden Bausteins sehr klar machen:

Zum Typ

Ein einzelner Buchstabe braucht natürlich viel weniger Speicherplatz als ein ganzer Text, eine kleine Ganzzahl weniger als eine Dezimalzahl mit 12 Nachkommastellen. Deshalb reserviert man nicht für jeden Wert, den man abspeichern möchte, gleich viel Speicher.

Stellen Sie sich ein grosses Containerschiff vor. Es gibt darauf eine grosse Menge von «Kisten», alle haben die gleiche Grösse. Darf in jeder Kiste nur höchstens ein Gegenstand sein (also z.B. ein Auto oder eine Banane), so würde ziemlich viel Platz auf dem Schiff verschwendet.
Auch im Computer beinhaltet jede Variable nur einen Wert. Um Speicherplatz effizient zu nutzen, werden also Kisten verschiedener Grössen und Formen benötigt.
Eine weitere Funktion des Variablentyps ist diejenige, bei der Interpretation des Kistenwertes zu helfen (s. Codierung).
Beispielsweise ist unter der Variablen mit dem Namen «vornamenInitial» der binäre Wert 01000100 zu finden. Falls es sich dabei um eine Variable vom Typ char (Zeichen) handelt, weiss der Computer, dass er bei einem Aufruf die ASCII Codierung anwenden soll; er gibt daher nicht die Zahl 68 sondern den Buchstaben D aus.

Nachfolgend eine kleine Übersicht zu einfachen Datentypen, später mehr dazu.

Quelle: Oinf

Zum Namen

Grundsätzlich kann man Variablennamen ziemlich frei aus Buchstaben und Zahlen zusammensetzen. Verboten ist dabei aber der Gebrauch von Spezialzeichen wie Leerzeichen, Umlauten, Akzenten und Satzzeichen. (Und natürlich muss ein Variablenname sich stets von jedem Schlüsselwort / reservierten Wort – wie z.B. «double» – unterscheiden.)

Damit wir den eigenen (und fremden) Quellcode besser lesen können, halten wir uns zudem an folgende Regeln (= Konventionen):

  • Wir schreiben Variablen klein; z.B. vorname statt Vorname.
  • Besteht eine Variable aus mehreren Teilwörtern, so schreiben wir bei jedem folgenden Teilwort den ersten Buchstaben gross (= camelCase); z.B. geburtsOrt statt geburtsort oder geburts_ort.
  • Wir verwenden selbsterklärende Variablennamen, also z.B. alterInJahren statt x.

Zum Wert

Vereinfacht gesagt: Der zu speichernde Wert muss dem Variablentyp entsprechen. Ist dies nicht der Fall, so gibt der Compiler eine Fehlermeldung aus. Das macht auch Sinn, denn wir haben ja sozusagen versucht, einen Tennisball in eine Pralinenschachtel zu stecken.

B) Umgang mit Variablen

1. Variablen deklarieren und Werte zuweisen

Um eine Variable benutzen zu können, müssen wir sie zunächst «deklarieren». Bildlich gesprochen heisst dies, dass wir die Kiste bauen (resp. einen Platz im Gestell reservieren) und anschreiben.

Die Befehlszeile

int meineZahl;

erstellt nun also eine Variable des Typs int (für integer, Ganzzahl) und gibt ihr den Namen meineZahl. Dabei steht der Typ immer vor dem Namen und das Ganze wird mit einem Semikolon (Strichpunkt) abgeschlossen. Weil ein Typ angegeben wird, wird hier eine neue Variable erstellt.

Der Editor kennt das Schlüsselwort int und stellt es mit roter Farbe dar.

Nun kann man dieser Variablen beliebig oft Werte zuweisen, also Dinge in die Kiste tun. Z.B. mit

meineZahl = 2;

Dabei gilt: Was rechts des Gleichheitszeichens steht wird genommen (ev. zuerst berechnet) und als Wert in die Variable links des Gleichheitszeichens geschrieben.
Man kann sich daher ein einzelnes Gleichheitszeichen im Programmcode immer auch als nach links gerichteten Pfeil vorstellen: meineZahl ← 2.

Selbstverständlich kann man rechts des Gleichheitszeichens auch die Namen bereits existierender Variablen verwenden. Falls ich also auf der Strasse eine Hunderternote finde, so kann ich den Effekt mit folgender Zuweisung ausdrücken:

meinVermoegen = meinVermoegen + 100;

Falls ich Röbi überfalle und mir all sein Geld aneigne, dann mit:

meinVermoegen = meinVermoegen + roebisVermoegen;
roebisVermoegen = 0;

Und wenn ich aus Reue die Hälfte meines Geldes der Kirche spende, so wirkt sich auch dies aus:

kirchenVermoegen = kirchenVermoegen + meinVermoegen/2; 
meinVermoegen = meinVermoegen/2;

Wenn es sich anbietet, kann man die Deklaration und Zuweisung einer Variable übrigens auch in einer einzigen Zeile erledigen:

int meineZahl = 7;

2. Variablen-Werte ausgeben

Die Ausgabe kann auf ganz vielfältige Weise geschehen. Wir wollen uns im Moment darauf beschränken, unsere Resultate in ein Text-Fenster (eine sogenannte Konsole) zu schreiben.

Dafür stellen wir Ihnen ein fast leeres Szenario zur Verfügung, es heisst ausgabe_in_konsole.zip.

Laden Sie herunter (Rechtsklick → Speichern unter), speichern Sie es auf Ihrem Home-Laufwerk (nicht in einem Cloud-Speicher). Da die Dateiendung .zip lautet, müssen Sie den Ordner entpacken (Rechtsklick → Alle extrahieren… oder, falls Sie 7-Zip installiert haben, Rechtsklick → 7-Zip → Entpacken nach «ausgabe_in_konsole\»). Es wird ein neuer Ordner («ausgabe_in_konsole») erstellt. Öffnen Sie diesen Ordner und starten Sie das Szenario in Greenfoot (auf die Datei project.greenfoot doppelklicken).
Wichtig: Obwohl Sie durch Doppelklick im Zip das Szenario öffnen könnten, würde es danach nicht funktionieren (sie können weder speichern noch mit Bildern arbeiten). Also: Unbedingt korrekt entpacken!

Das Szenario besteht aus einer fast leeren Welt, einzig bestückt mit einer Instanz der Klasse Beispiel (zu erkennen am grünen Symbol links oben).

Quelle: Oinf

Öffnen Sie die Klasse „Beispiel“ im Editor.

Sie sehen, dass die act()-Methode im Moment noch leer ist. Wir ergänzen diese nun folgendermassen:

public void act()
{
    int meineZahl=2; // Variable deklarieren und Wert zuweisen
    System.out.println(meineZahl); // Wert in Konsolenfenster ausgeben
}

Vgl. auch nachfolgende Abbildung

Quelle: Oinf

Greenfoot kompiliert laufend (der Compile-Knopf muss in der Regel daher nicht gedrückt werden).
Klicken Sie im Hauptfenster nun auf die > Act-Schaltfläche.

Die act()-Methode wird aufgerufen und unser Code ausgeführt. Dabei wird ein Fenster geöffnet und die Zahl ausgegeben.

Sehr spannend ist das Programm bis jetzt noch nicht; verändern wir daher die Variable vor der Ausgabe noch.
Fügen Sie die zusätzliche Zeile ein:

public void act()
{
    int meineZahl=2; // Variable deklarieren und Wert zuweisen
    meineZahl = meineZahl + 1; // Wert verändern
    System.out.println(meineZahl); // Wert in Konsolenfenster ausgeben
}

Kompilieren und testen Sie.

Jedesmal, wenn wir auf die > Act-Schaltfläche klicken, wird die gleiche Zahl ausgegeben. Dies liegt daran, dass die Variable meineZahl am Anfang der act()-Methode – also bei jedem Klick – neu erstellt und mit einer 2 gefüllt wird.

3. Instanzvariablen verwenden

Damit sich die Ausgabe verändert, müssen wir die wiederholte Neuerschaffung der Variable verhindern. Wir deklarieren und initialisieren (die allererste Zuweisung nennt man Initialisierung) daher die Variable nicht innerhalb einer Methode (gelb hinterlegt), sondern als sogenannte „Instanzvariable“ direkt in der Beispiel-Klasse – d.h. innerhalb des grün hinterlegten Klassen-Blocks, aber nicht in einem der gelb hinterlegten Methoden-Blöcke.
Dazu verschieben wir die entsprechende Zeile nach oben (in der Abbildung grün umrahmt).

Quelle: Oinf

Die Variable wird jetzt ausserhalb der act()-Methode deklariert und initialisiert, also nur einmal, ganz zu Beginn, noch bevor irgend etwas anderes passieren konnte. Der Code innerhalb der act()-Methode arbeitet jetzt mit der bereits existierenden Variablen meineZahl (kein Typ angegeben, also keine neue Variable) und zwar, indem er zum aktuellen Wert eins dazu zählt und das Ergebnis unter demselben Namen abspeichert. Bei jedem Aufruf der act()-Methode wird also der Wert von meineZahl vergrössert und dann ausgegeben.

Wie Sie sehen, kann es einen Unterschied machen, wo im Code eine Variable deklariert, also erschaffen wird. Eine Variable, die innerhalb einer Methode (im Editor erkennbar an der gelben Schattierung) deklariert wird, lebt nur innerhalb dieser Methode. Das bedeutet zum einen, dass sie neu erschaffen wird, wenn diese Methode aufgerufen wird. Zum anderen heisst es auch, dass ich diese Variable nicht ausserhalb dieser Methode (bspw. in einer anderen Methode) benutzen kann.

Instanzvariablen dagegen erlauben genau das: Jede Methode innerhalb einer Klasse (also einem Editorfenster, genauer: dem grün hinterlegten Bereich) kann auf diese Variable zugreifen und ihren momentanen Wert benutzen, oder auch verändern (mit einer Zuweisung). Eine Variable ist genau dann eine Instanzvariable, wenn sie zwar innerhalb des grünen Bereichs (der Klasse), aber nicht innerhalb eines gelben Bereichs (den Methoden) deklariert wird. Üblicherweise macht man das gleich ganz oben (s. Abbildung). Code, der an dieser Stelle steht, wird nur ein einziges Mal ausgeführt, nämlich ganz am Anfang (meist mit der Erschaffung der Welt; genauer: wenn eine Instanz der entsprechenden Klasse – hier Beispiel – erschaffen wird). Falls, wie oben, die Instanzvariable hier auch gleich initialisiert wird, dann gilt dieser Wert zu Beginn – aber nur solange der Wert dieser Variablen nicht vom Code in einer Methode verändert wird (s. oben, beim Aufruf von act() wird der Wert in der Kiste um 1 erhöht, und das bleibt dann so, bis er sich erneut ändert).

Aufgabe

Lösen Sie hierzu vom Aufgabenblatt die Aufgaben zu den Integer-Variablen: Greenfoot_Variablen.pdf.

4. Einfache Figuren zeichnen

Laden Sie sich das Szenario JoeVariablen.zip herunter. (Wie immer: Erst entpacken, dann öffnen.)
(Wenn es Fehlermeldungen gibt, allenfalls die alte Variante nutzen: JoeVariablen_greenfoot3.0.3.zip)

Drücken Sie dreimal auf > Act und betrachten Sie das Resultat.

Analysieren Sie nun den Code der Klasse «Joe» und versuchen Sie, das Ergebnis nachzuvollziehen.

Ändern Sie die Act-Methode jetzt so ab, dass Sie jeweils eine der nachfolgend abgebildeten vier Figuren erhalten:
(Tipp zu Figur 4: Nicht die Distanz ändern, sondern den Winkel.)

Quelle: OInf.ch

5. Weitere Variablentypen

Nebst den Ganzzahlen sind für uns zunächst vor allem Zeichen und Zeichenketten sowie Fliesskommazahlen wichtig.

Ein einzelnes Zeichen wird als char gespeichert. Eine Zeichenkette als String (es kann allerdings sein, dass eine Zeichenkette manchmal auch nur aus einem Zeichen besteht, oder sogar aus gar keinem).

Für Fliesskommazahlen stehen die Datentypen float und double zur Verfügung. Double kann mehr Nachkommastellen speichern, braucht aber doppelt so viel Platz.

Öffnen Sie das «ausgabe-in-konsole»-Szenario und probieren Sie folgenden Code in der Act-Methode der Klasse Beispiel aus:

char meinVornamenInitial = 'H'; // Zeichen: einfache Anführungszeichen
String meinVorname = "Hans"; // Zeichenkette: doppelte Anführungszeichen
double meineSchuhgroesse = 43.5; // Fliesskommazahl doppelter Genauigkeit

Achtung: Der Typbezeichner String wird gross geschrieben! Auch wird er – im Gegensatz zu den anderen Typen – vom Editor nicht rot dargestellt.

Nun kann man Textteile verknüpfen und ausgeben lassen.

System.out.println("Mein Vorname lautet " + meinVorname + ".");

Der Operator + steht hier nicht für die Addition, sondern für die Verknüpfung zweier Zeichenketten, der sogenannten «Konkatenation».

Verknüpft man eine Zeichenkette mit einer Zahl, so wird die Zahl vor dem Verketten automatisch in eine Zeichenkette umgewandelt:

System.out.println("Meine Schuhgroesse ist " + meineSchuhgroesse + ".");

Aufgabe

Lösen Sie vom Aufgabenblatt die Aufgaben zu den verschiedenen Variablentypen: Greenfoot_Variablen.pdf. Verwenden Sie dabei wiederum das einfache «ausgabe-in-konsole»-Szenario.

6. Benutzereingaben

Setzen Sie folgenden Code in die Act-Methode und testen Sie das Programm:

String meinName = Greenfoot.ask("Wie lautet Dein Vorname?");
int meinAlter = Integer.parseInt(Greenfoot.ask("Wie alt (in ganzen Jahren) bist Du?"));
System.out.println("Du heisst also "+ meinName + " und bist " + meinAlter + " Jahre alt." );

Sie sehen:

  • Es wird zweimal eine Eingabe verlangt. Zuerst ein Text, danach eine Zahl.
  • Da die Methode Greenfoot.ask() immer einen Text zurückliefert, muss dieser mit Integer.parseInt() noch in eine Zahl umgewandelt werden.

Sie müssen die Details im Moment nicht verstehen, es reicht, wenn Sie diesen Code anwenden können.

Aufgabe

Lösen Sie vom Aufgabenblatt die Aufgaben mit Nutzereingaben: Greenfoot_Variablen.pdf.

7. Gültigkeit und Sichtbarkeit von Variablen

Stellen Sie sich vor, dass Sie ein langes Programm schreiben, das Sie auf mehrere Unterprogramme aufteilen. Sie wollen nun natürlich nicht jedesmal überlegen, ob Sie (oder allenfalls einer der Programmierer-Kollegen, die am gleichen grossen Programm arbeiten) irgendwo einen Variablennamen in einem Teilprogramm bereits eingesetzt haben.
Daher ist es praktisch, dass man Gültigkeit und Sichtbarkeit von Variablen unterscheiden kann:

Gültigkeit vs. Sichtbarkeit

Gültigkeits-Bereich: Programmbereich, in dem die Variable existiert (d.h. einen Speicherplatz behält).
Sichtbarkeits-Bereich: Programmbereich, in welchem auf die Variable zugegriffen werden kann.

Beispiel:

public class Beispiel extends Actor
{
    int i=1; // Instanzvariable
    
    public void act() 
    {
        System.out.println(i);
        neueMethode();
        System.out.println(i);
    }    
    
    public void neueMethode() {
        int i=2; // Methodenvariable
        System.out.println(i);
    }
}

Die Instanz-Variable i (mit Wert 1) ist gültig und behält ihren Wert, solange die Instanz existiert.
Die Methoden-Variable i (mit Wert 2) ist gültig während der Laufzeit von neueMethode. In dieser Zeit verdeckt sie die Instanz-Variable: diese ist also während der Laufzeit von neueMethode nicht sichtbar und nicht nutzbar, behält aber ihren Wert.

Der Code liefert folglich die Ausgabe

1
2
1