Java Tutorial #2 - "Süßigkeitenorganisation"

Benutzeravatar
Zweistein2
Administrator
Beiträge: 93
Registriert: Di Apr 23, 2013 6:43 pm

Java Tutorial #2 - "Süßigkeitenorganisation"

Beitragvon Zweistein2 » Fr Jan 17, 2014 5:46 pm

Heyho,

Und willkommen zu Teil 2!

#2 - "Süßigkeitenorganisation"


Ich warne gleich mal vor. Im Laufe der Tutorials wird die Menge an Code steigen. Da ihr aber Vieles schon kennt, sollte das nicht allzuschwer zum Verstehen sein. Dennoch kann ich den Code hier nicht einfach reinschreiben, das würde spätestens beim nächsten Tutorial den Rahmen sprengen. Daher uppe ich die BlueJ-Projekt-Dateien samt Code auf Dropbox und verlinke dann darauf. Ihr müsst dann nurnoch die Dateien herunterladen und die Projekt-Datei öffnen.

Nachfolgend dann auch der Download-Link für dieses Tutorial: *klick*

In diesem Tutorial verwenden wir ein Süßigkeitenverteilsystem, welches Schokolade oder Lollis an Peter, bzw. seine kleine Schwester Lisa verteilt.

Nun gut, fangen wir an!

Code: Alles auswählen

import java.util.Random;

public class Game
{
    Peter peter;
    Random random;   
   
    public Game()
    {
        //Kinder erstellen
        peter = new Peter();
       
        //Zufallsgenerator erstellen
        random = new Random();
       
        //Eine zufällige Zahl zwischen 0 und 1 wird X und eine 2te zufällige Zahl Y zugewiesen
        int X;
        X = random.nextInt(2);
        int Y = random.nextInt(2);
       
        NaschsachenVerteilen(X, Y);
    }
   
    public void NaschsachenVerteilen(int x, int y)
    {
        if(x == 0)
        {
            if(y == 0)
            {
                System.out.println("Lisa bekommt einen Lolli!");
                lolli.Verteilen(lisa);
            }else
            if(y == 1)
            {
                System.out.println("Peter bekommt einen Lolli!");
                lolli.Verteilen(peter);
            }else
            {
                System.out.println("Das ist komisch O.o!");
            }           
        }else
        {
            ...
        }
    }
}


So, hier kommen gleich mehrere neue Sachen hinzu. Das Erste was euch auffallen wird, ist folgende Zeile:

Code: Alles auswählen

import java.util.Random;

Nun, diese Zeile importiert die Java-Klasse "Random" aus Java. Dadurch können wir nun zufällige Zahlen generieren lassen, ohne dafür eine Funktion bauen zu müssen, indem wir einfach die Methoden der Random-Klasse benutzen.

Auch diese Zeile hier ist neu:

Code: Alles auswählen

Peter peter;


Wie ihr vlt. schon bemerkt habt, ist in dem obigen Download auch eine Peter-Klasse enthalten. Die obige Zeile macht nun nichts anderes, als eine Variable mit dem Typ "Peter" (also der Klasse) und dem Namen "peter" zu deklarieren. (int X; hat denselben Effekt. Es deklariert eine Variable des Typs "int" namens "X"). Das ist sehr nützlich. So könnten wir beispielsweise mehrere Versionen von Peter erstellen (wenn z.b. 2 versch. Peter anwesend sind und Süßigkeiten wollen) ohne dass sie sich beeinflussen. Wie genau das funktioniert sehen wir dann aber bei den abstrakten Klassen. Nach demselben Prinzip arbeitet auch die Zeile darunter.

Code: Alles auswählen

//Kinder erstellen
peter = new Peter();


"//Kinder erstellen" ist ein Kommentar. Kommentare beginnen mit // und werden vom Compiler nicht auf Fehler überprüft und auch nicht versucht auszuführen. Damit kann man z.B.: den Code dokumentieren, so wie oben, oder nicht funktionierenden Code "ausklammern" wenn man sein Programm trotzdem testen/spielen möchte, bis man den Fehler behoben hat.

Wie ihr ja wisst, muss man nachdem man eine Variable deklariert hat diese initialisieren. Das passiert mit "peter = new Peter();". Doch was macht "new Peter();" eigentlich?
Nun, damit wird die Klasse Peter erstellt und der Variable "peter" zugewiesen. Diese Erstellung hat zur Folge, dass der Konstruktor der Klasse Peter aufgerufen wird. Es ist ganz wichtig, Klassen erst zu erstellen, bevor man Funktionen darin aufruft, sonst bekommt man eine Fehlermeldung!

Code: Alles auswählen

int X;
X = random.nextInt(2);
int Y = random.nextInt(2);


Doch wie rufe ich eine Methode aus einer anderen Klasse überhaupt auf?

Wie ihr seht haben wir oben ja schon eine Random-Variable namens "random" erstellt und dieser eine neue Random-Klasse zugewiesen. Hier wird davon Gebrauch gemacht: "random.nextInt(2);". Diese kleine Zeile ist der Methoden-Aufruf der nextInt()-Funktion in der Klasse Random!

Einen klassenfremder Methodenaufruf sieht im Endeffekt wie folgt aus:

VariableDerKlasse.Methodenname(Anfangsparameter);

Nun, wie der Name und auch der Kommentar schon sagen, "nextInt(2);" macht einfach eine Zufallszahl zwischen 0 und 1. (PC fängt bei 0 zu zählen an, daher auch die 2, obwohl die Zufallszahl nur von 0 - 1 geht. Wenn man z.B.: eine Zufallszahl zwischen 0 und 13 möchte, schreibt man "nextInt(14);" )

Doch noch etwas ist neu. X wird noch so deklariert und initialisiert, wie wir es gelernt haben. Y hingegen macht beides auf einmal. Es wird also zeitgleich deklariert und initialisiert.

Auch die Stelle, an der sie deklariert und initialisiert werden ist anders. Normalerweise macht man das direkt nach dem Klassenkopf. Dann sind die Variablen in der gesamten Klasse verfügbar und können von jeder Methode im Klassenrumpf aufgerufen/benutzt werden. Hier jedoch werden sie innerhalb der Methode deklariert und initialisiert und sind dementsprechend nur innerhalb dieser Methode verfügbar. Eine 2te Methode innerhalb der Klasse würde also nicht auf diese Variablen zugreifen können und einen Fehler auswerfen. Eine Variable kann man aber nicht global (also von allen Klassen innerhalb des Projekts) deklarieren. Man kann dennoch auf Variablen anderer Klassen zugreifen, indem man wieder auf unsere Variable von Peter zugreift. So kann man mit "peter.Name = "Hans";" den Namen von Peter zu Hans ändern.

Es gilt also genau wie beim Methodenaufruf bei fremden Klassen:

VariableDerKlasse.Variablenname

Code: Alles auswählen

if(y == 0)
{
    System.out.println("Lisa bekommt einen Lolli!");
    lolli.Verteilen(lisa);
}else
if(y == 1)
{
    System.out.println("Peter bekommt einen Lolli!");
    lolli.Verteilen(peter);
}else
{
    System.out.println("Das ist komisch O.o!");
}


Neu sind auch die if-else-Blöcke hier. Doch die sind ganz einfach und auch sehr nützlich. Nun zu Erklärung:

Code: Alles auswählen

if(Bedingung)
{
    sollte das stimmen, dann mach das hier.
}else
{
    falls nicht kommt das hier.
}


bzw. "übersetzt":

Code: Alles auswählen

Falls(Bedingung)
{
    wahr, dann das
}Sonst
{
    das
}


Also, sollte "y" den Wert 0 haben, so bekommt Lisa einen Lolli. Wenn "y" nicht 0 ist, dann wird überprüft ob sie 1 ist. Sollte das der Fall sein, so bekommt Lisa Schokolade. Sollte "y" weder 1 noch 0 sein, so kommt eine Fehlermeldung ("Das ist komisch O.o!"). Wie ihr seht, könnt ihr auch mehrere if-else-Blöcke verschachteln.

Code: Alles auswählen

public abstract class Naschsachen
{
    public String Name;
    public int EmpfohlenesAlter;
    public int ID;

    public void Verteilen(Kinder Kind)
    {
        if(Kind.Alter >= EmpfohlenesAlter)
        {
            for(int i = 0; i <= 19; i++)
            {
                if(Kind.NaschsachenInventar[i] == 0)
                {
                    Kind.NaschsachenInventar[i] = ID;
                }else
                {
                    System.out.println(Kind.Name + " hat schon alle Hände voll mit Süßem!");
                }
            }
        }else
        {
            System.out.println(Kind.Name + " ist zu jung für diese Süßigkeit!");
        }
    }
}


Kommen wir mal zur Naschsachen-Klasse. Wie ihr seht, ist es keine normale Klasse mehr, sondern eine abstract class, also eine Abstrakte Klasse. Eine abstrakte Klasse ist soetwas wie eine Vorlage, auf der andere Klassen basieren. Daher kann sie auch nicht mit "Naschsachen naschsachen = new Naschsachen();" erstellt werden.

-> Abstrakte Klassen lassen sich nicht erstellen!

Code: Alles auswählen

public class Lolli extends Naschsachen
{
    public Lolli()
    {
        Name = "Lolli";
        EmpfohlenesAlter = 10;
        ID = 1;
    }
}


Unsere Lolli-Klasse zum Beispiel übernimmt die Variablen und die Methode "Verteilen();" der Naschsachen-Klasse. Das ist durch das Schlüsselwort extends (zu deutsch: erweitert (um)) und dem Namen der abstrakten Klasse deutlich. Das heißt im Java-Fachjargon erben. Die Lollie-Klasse erbt also von der Naschsachen-Klasse und übernimmt somit Variablen-Deklarationen und Methoden.

Das hat den Vorteil, dass sowohl Lolli, als auch Schokolade gleiche Variablentypen und -namen, sowie Methoden nutzen können, ohne diese jedes Mal doppelt und dreifach schreiben zu müssen. Dennoch kann man z.B.: für Lolli weitere Variablen/Methoden hinzufügen, die dann in Schokolade nicht vorhanden sind/sein müssen.

Zu guter Letzt noch 3 Dinge, die neu sind:

Code: Alles auswählen

public void Verteilen(Kinder Kind)


Hier wird die Variable "Kind" des Typs Kinder übergeben. Das ist im Prinzip wie unsere "peter"-Variable vom Anfang des Tutorials. Doch diesmal ist Kinder eine abstrakte Klasse. Wie ihr ja schon wisst, kann man sie nicht erstellen. Doch was wird hier dann genau übergeben?

Nun, der Methodenaufruf ist wie folgt:

"lolli.Verteilen(lisa);"
bzw.
"lolli.Verteilen(peter);"

Es wird also eine der erbenden Klassen (Hier Peter, bzw. Lisa) übergeben.

-> Eine abstrakte Klasse als Variablentyp lässt alle erbenden Klassen von jener abstrakten Klasse als Typ zu.

Code: Alles auswählen

public int[] NaschsachenInventar;


Das hier ist auch neu (und steht in der Kinder-Klasse). Was ihr hier seht ist ein eindimensionales Array, also ein Feld des Typs int. Ein Array ist ein Feld fester Große, welches mehrere versch. Werte desselben Typs speichern kann. In unserem Fall hier ist das Array 20 "Plätze" groß, kann also 20 versch. int-Werte speichern.

Code: Alles auswählen

NaschsachenInventar = new int[20];


Die Größe wird auf diese Art und Weise festgelegt. (Bedenkt das der PC wieder bei 0 beginnt zu zählen, ihr hier also die Plätze 0-19 befüllen könnt).

Code: Alles auswählen

for(int i = 0; i <= 19; i++)
{
    if(Kind.NaschsachenInventar[i] == 0)
    {
        Kind.NaschsachenInventar[i] = ID;
    }else
    {
        System.out.println(Kind.Name + " hat schon alle Hände voll mit Süßem!");
    }
}


Zu guter Letzt noch die for-Schleife. Die Anweisung(en) im Inneren der for-Schleife werden solange wiederholt, bis die Abbruchbedinung zutrifft. Wichtig ist, dass die Abbruchbedingung auch zutreffen kann! Sollte dies nicht der Fall sein, wird die Schleife unendlich oft wiederholt und euer Programm hängt sich auf/schießt eure CPU ab, sodass sich der PC aufhängt. Hier mal allgemein der Aufbau einer solchen Schleife:

Code: Alles auswählen

for(Variable; Abbruchbedingung; WasNachJedemDurchlaufPassierenSoll)
{
    Anweisungen, die wiederholt werden sollen
}


In unserem Fall erstellen wir also eine Variable des Typs int mit dem Wert 0 (Deklarieren und Initialisieren sie also): "int i = 0;", dann definieren wir die Abbruchbedinung. Abgebrochen wird, sobald i den Wert 19 oder größer hat (also das komplette Array durchgegangen ist.) Nach jedem Durchlauf wird i um 1 erhöht. Dies geschieht mithilfe von i++, einem Postinkrement (Dass das nicht so ganz ungefährlich ist, bzw. was genau ein Postinkrement ist, kommt in späteren Tutorials).

Unsere for-Schleife durchsucht also das komplette Array nach leeren Plätzen. Sofern sie einen findet, füllt sie ihn mit dem entsprechenden Naschwerk (bzw. dessen ID) und bricht ab, indem sie i auf 30 setzt und so die Abbruchbedingung erfüllt. Sollten alle Plätze belegt sein, kommt eine entsprechende Meldung.
BildBild

Zurück zu „Java“

Wer ist online?

Mitglieder in diesem Forum: 0 Mitglieder und 1 Gast