Benutzer-Werkzeuge

Webseiten-Werkzeuge


klassen2:constructors:start

Unterschiede

Hier werden die Unterschiede zwischen zwei Versionen angezeigt.


klassen2:constructors:start [2024/08/31 10:03] (aktuell) – angelegt - Externe Bearbeitung 127.0.0.1
Zeile 1: Zeile 1:
 +====== Konstruktoren ======
  
 +{{youtube>y0az0x-mHx4?medium}}
 +
 +Wir haben inzwischen schon viele Objekte instanziert, oft auch mit der Angabe von Parametern. Das folgende Programm instanziert beispielsweise ein Objekt der Klasse ''Rechteck'' und übergibt die Parameter (50, 50, 400, 300) für die Koordinaten der linken oberen Ecke (50, 50), die Breite (400) und die Höhe (300).
 +<HTML>
 +
 +<div class="java-online" style="height: 200px; width: 100%" data-java-online="{'withBottomPanel': false, 'id': 'Konstruktoren1'}">
 +
 +<script type="text/plain" title="Beispiel.java">
 +new Rectangle(50, 50, 400, 300);
 +</script>
 +
 +</div>
 +
 +</HTML>
 +<WRAP center round info 60%>
 +Beim Instanzieren eines neuen Objekts mithilfe des Schlüsselwortes ''new'' wird immer eine Methode aufgerufen, die das Objekt initialisiert. Diese Methode wird **Konstruktor** genannt. Werden zusätzliche Parameter angegeben, z.B. ''new Rectangle(50, 50, 400, 300)'', so bekommt der Konstruktor diese als Parameterwerte übergeben.
 +</WRAP>
 +
 + Wir lernen in diesem Kapitel, wie wir die Konstruktoren unserer Klassen selbst schreiben können.
 +
 +===== Beispiel 1: Würfel =====
 +Programmiere eine Klasse ''Würfel'', die einen n-seitigen Würfel simuliert. Die Zahl der Seiten soll schon beim Instanzieren mit angegeben werden, ein Hauptprogramm könnte also so aussehen:
 +<code MyJava>
 +Würfel w6 = new Würfel(6);     // Würfel-Objekt mit 6 Seiten
 +Würfel w20 = new Würfel(20);   // Würfel-Objekt mit 20 Seiten
 +println(w6.würfle());
 +println(w20.würfle());
 +</code>
 +
 +<HTML>
 +
 +<div class="java-online" style="height: 400px; width: 100%" data-java-online="{'withBottomPanel': false, 'id': 'Konstruktoren1a'}">
 +
 +<script type="text/plain" title="Beispiel1a.java">
 +Würfel w6 = new Würfel(6);     // Würfel-Objekt mit 6 Seiten
 +Würfel w20 = new Würfel(20);   // Würfel-Objekt mit 20 Seiten
 +println(w6.würfle());
 +println(w20.würfle());
 +
 +class Würfel{
 +   int seitenzahl;
 +   
 +   // Das ist die Konstruktor-Methode ("der Konstruktor") dieser Klasse. Du erkennst sie daran, 
 +   // dass sie den Bezeichner der Klasse ("Würfel") trägt und kein Rückgabedatentyp angegeben ist.
 +   Würfel(int s){
 +      seitenzahl = s;
 +   }
 +   
 +   int würfle(){
 +      return Math.floor(Math.random()*seitenzahl) + 1;
 +   }
 +}
 +</script>
 +</div>
 +</HTML>
 +
 +
 +
 +===== Beispiel 2: Buntstift =====
 +Schau' Dir das folgende Beispielprogramm an und überlege Dir, an welchen Stellen des Programms der Konstruktor ''Buntstift(Color farbe1)'' aufgerufen wird und welchen Zweck er hat.
 +
 +<HTML>
 +
 +<div class="java-online" style="height: 400px; width: 100%" data-java-online="{'withBottomPanel': false, 'id': 'Konstruktoren2'}">
 +
 +<script type="text/plain" title="Beispiel.java">
 +Buntstift rotstift = new Buntstift(Color.red);
 +rotstift.schreibe("Hallo Welt!");
 +
 +Buntstift grünstift = new Buntstift(Color.lime);
 +grünstift.schreibe("Das ist grün");
 +rotstift.schreibe("Das ist wieder rot");
 +
 +class Buntstift {
 +
 +   Color farbe;
 +
 +   // Das ist die Konstruktor-Methode ("der Konstruktor") dieser Klasse. Du erkennst sie daran, 
 +   // dass sie den Bezeichner der Klasse ("Buntstift") trägt und kein Rückgabedatentyp angegeben ist.
 +   Buntstift(Color farbe1) {
 +      farbe = farbe1;
 +   }
 +
 +   void schreibe(String text) {
 +      println(text, farbe);
 +   }
 +
 +}
 +</script>
 +</div>
 +</HTML>
 +===== Aufgabe =====
 +Führe das Programm Schrittweise mit "step into ({{:klassen2:constructors:step-into-dark.png?nolink|}})" aus und beobachte, in welcher Reihenfolge die Programmzeilen durchlaufen werden!
 +
 +Die Definition des Konstruktors der Klasse ''Buntstift'' ist in den Zeile 11 - 13 zu finden:
 +
 +<code learnj [enable_line_numbers="true", start_line_numbers_at="11"]>
 +   public Buntstift(Color farbe1) {
 +      farbe = farbe1;
 +   }
 +</code>
 +
 +<WRAP center round info 60%>
 +Eine **Konstruktordefinition** sieht aus wie die Definition einer "normalen" Methode, mit zwei Unterschieden:
 +  * Sie besitzt keinen Rückgabetyp.
 +  * Ihr Bezeichner stimmt exakt mit dem Bezeichner der Klasse überein.
 +Findet der Compiler eine Methodendefinition mit diesen Eigenschaften, so erkennt er sie als Konstruktor der Klasse. Beim Instanzieren eines neuen Objekts mittels ''new'' (hier: ''new Buntstift(Color.red)'') wird der Konstruktor automatisch ausgeführt. Dabei werden die in Klammern angegebenen Werte (hier: ''Color.red'') als Parameterwerte übergeben.
 +</WRAP>
 +Im Falle der Klasse ''Buntstift'' besitzt die Konstruktordefinition den Parameter ''Color farbe1''. Da der Wert jedes Parameters nach abgeschlosssener Ausführung der Methode verworfen wird (in unserem Fall also dann, wenn der Computer beim Ausführen des Konstruktors in Zeile 13 angelangt ist), müssen wir ihn "retten", damit er im weiteren Programmverlauf benutzt werden kann. Das machen wir, indem wir ihn in Zeile 12 in das Attribut ''farbe'' kopieren:
 +<code learnj [enable_line_numbers="true", highlight_lines_extra="2", start_line_numbers_at="11"]>
 +   public Buntstift(Color farbe1) {
 +      farbe = farbe1;
 +   }
 +</code>
 +
 +===== Das Schlüsselwort "this" =====
 +Hat es Dich gewundert, warum wir den Parameter im Konstruktor oben ''farbe1'' genannt haben und nicht ''farbe''? Probier' im folgenden Kasten mal aus, was passiert, wenn wir ihn einfach umbenennen:
 +<HTML>
 +<div class="java-online" style="height: 500px; width: 100%" data-java-online="{'withBottomPanel': true, 'id': 'Konstruktoren3'}">
 +<script type="text/plain" title="Beispiel.java">
 +Buntstift rotstift = new Buntstift(Color.red);
 +rotstift.schreibe("Hallo Welt!");
 +
 +class Buntstift {
 +
 +   Color farbe;
 +
 +   public Buntstift(Color farbe) {
 +      farbe = farbe;
 +   }
 +
 +   public void schreibe(String text) {
 +      println(text, farbe);
 +   }
 +
 +}
 +</script>
 +</div>
 +</HTML>
 +Führe das Programm wieder Schrittweise mit "step into ({{:klassen2:constructors:step-into-dark.png?nolink|}})" aus. Verstehst Du, warum es beim Ausführen zum Fehler kommt?
 +
 +<WRAP center round tip 60%>
 +**Tipp:** Klicke mit der Maus auf den Bezeichner ''farbe''. Alle Vorkommen der Parametervariable werden dann markiert.
 +</WRAP>
 +
 +Das Problem besteht darin, dass der Parameter ''farbe'' jetzt das Attribut ''farbe'' **überdeckt**. Dadurch bewirkt die Anweisung
 +<code learnj>
 +farbe = farbe;
 +</code>
 +in Zeile 9, dass der Wert des Parameters ''farbe'' mit seinem eigenen Wert überschrieben wird. Der Wert des **Attributs** ''farbe'' wird nicht verändert, bleibt also ''null'' und führt so in Zeile 13 zum Fehler. \\ \\ 
 +Wir müssen dem Compiler irgendwie mitteilen, dass der Bezeichner ''farbe'' auf der linken Seite der Zuweisung für das **Attribut** ''farbe'' steht, nicht für den Parameter ''farbe''. Dies können wir mithilfe des Schlüsselwortes ''this'' erreichen: ''this'' steht nämlich immer für dasjenige Objekt, //"in dem"// wir uns gerade befinden. Im Bereich Zeile 8 - 10 also für das Objekt, das gerade erzeugt wird. ''this.farbe'' ist damit eindeutig dessen **Attribut** farbe. Wir ersetzen Zeile 9 also durch
 +<code learnj>
 +this.farbe = farbe;
 +</code>
 +Klicke im unteren Beispiel auf die verschiedenen Vorkommen des Bezeichners ''farbe'' und achte darauf, welche davon jeweils als zusammengehörig markiert werden!
 +<HTML>
 +<div class="java-online" style="height: 400px; width: 100%" data-java-online="{'withBottomPanel': false, 'id': 'Konstruktoren4'}">
 +<script type="text/plain" title="Beispiel.java">
 +Buntstift rotstift = new Buntstift(Color.red);
 +rotstift.schreibe("Hallo Welt!");
 +
 +class Buntstift {
 +
 +   Color farbe;
 +
 +   public Buntstift(Color farbe) {
 +      this.farbe = farbe;
 +   }
 +
 +   public void schreibe(String text) {
 +      println(text, farbe);
 +   }
 +
 +}
 +</script>
 +</div>
 +</HTML>
 +
 +===== Beispiel 3: Polynomrechner =====
 +Die Klasse ''PolynomZweitenGrades'' repräsentiert ein Polynom 2. Grades, also einen Term der Form $ax^2+bx+c$. Die Werte für die Konstanten a, b und c werden beim Instanzieren des Objekts dem Konstruktor übergeben und in den entsprechenden Attributen gespeichert, so dass dann in der Methode ''getWert(double x)'' für jeden beliebigen Wert von x der Wert des Polynoms berechnet werden kann. 
 +
 +<HTML>
 +
 +<div class="java-online" style="height: 400px; width: 100%" data-java-online="{'withBottomPanel': false, 'id': 'Konstruktoren5'}">
 +
 +<script type="text/plain" title="Polynomrechner.java">
 +PolynomZweitenGrades p = new PolynomZweitenGrades(1, 2, -3);    // Definiert das Polynom 1x^2+2x-3
 +println("p(4) = " + p.getWert(4));
 +println("p(-1) = " + p.getWert(-1));
 +
 +class PolynomZweitenGrades {
 +   double a;
 +   double b;
 +   double c;
 +
 +   public PolynomZweitenGrades(double a, double b, double c) {
 +      this.a = a;
 +      this.b = b;
 +      this.c = c;
 +   }
 +
 +   public double getWert(double x) {
 +      return a * x * x + b * x + c;
 +   }  
 +}
 +</script>
 +</div>
 +</HTML>
 +
 +
 +===== Aufgabe 1: Die Klasse Bruch =====
 +Im vorhergehenden Kapitel haben wir eine [[[klassen2:attribute:start#aufgabe_4eine_klasse_zum_bruchrechnen|Klasse zum Bruchrechnen]] kennengelernt. Erweitere sie um einen Konstruktor, der Zähler und Nenner als Parameter entgegennimmt, so dass man statt
 +<code myJava>
 +Bruch b1 = new Bruch();
 +b1.zähler = 3;
 +b1.nenner = 4;
 +</code>
 +einfach schreiben kann
 +<code myJava>
 +Bruch b1 = new Bruch(3,4);
 +</code>
 +
 +<HTML>
 +
 +<div class="java-online" style="height: 500px; width: 100%" data-java-online="{'withBottomPanel': true, 'id': 'Konstruktoren5'}">
 +
 +<script type="text/plain" title="Bruch.java">
 +
 +Bruch b1 = new Bruch(4, 3);
 +Bruch b2 = new Bruch(1, 2);
 +b1.ausgabeUnecht();
 +b1.ausgabeEcht();
 +b1.mal(b2);
 +b1.ausgabeUnecht();
 +
 +class Bruch {
 +
 +   int z;
 +   int n;
 +
 +   // Hier fehlt der Konstruktor!
 +
 +   public void ausgabeUnecht() {
 +      println(z + "/" + n);
 +   }
 +
 +   public void ausgabeEcht() {
 +
 +      int a1 = z;
 +
 +      if(Math.abs(z) >= n) {
 +         int ganzerAnteil = z / n;
 +         a1 = z - ganzerAnteil * n;
 +         if(a1 < 0) {
 +            a1 = -a1;
 +         }
 +         print(ganzerAnteil + " ");
 +      }
 +      
 +      println(a1 + "/" + n);
 +      
 +   }
 +
 +   public void mal(Bruch b2) {
 +      
 +      z = z * b2.z;
 +      n = n * b2.n;
 +
 +      kürze();
 +
 +   }
 +
 +   public void geteilt(Bruch b2) {
 +      
 +      z = z * b2.n;
 +      n = n * b2.z;
 +
 +      kürze();
 +
 +   }
 +
 +   public void addiere(Bruch b2) {
 +
 +      // a/b + c/d = (a*d)/(b*d) + (c*b)/(d*b) = (a*d + c*b)/(b*d)
 +
 +      z =(z * b2.n + b2.z * n);
 +      n = n * b2.n;
 +
 +      kürze();
 +
 +   }
 +
 +   public void subtrahiere(Bruch b2) {
 +
 +      // a/b - c/d = (a*d)/(b*d) - (c*b)/(d*b) = (a*d - c*b)/(b*d)
 +
 +      z =(z * b2.n - b2.z * n);
 +      n = n * b2.n;
 +
 +      kürze();
 +
 +   }
 +
 +   public void kürze() {
 +      
 +      for(int i = 2; i <= Math.sqrt(Math.abs(z)); i++) {
 +         
 +         if(z % i == 0 && n % i == 0) {
 +            z = z / i;
 +            n = n / i;
 +         }
 +
 +      }
 +
 +   }
 +}
 +
 +</script>
 +
 +</div>
 +</HTML>
 +[[.loesung:aufgabe1:start|Hier geht's zur Lösung!]]
 +
 +===== Aufgabe 2: Die Klasse Tier =====
 +Füge der [[klassen2:attribute:start#aufgabe_1tiere|Klasse Tier aus dem vorangegangenen Kapitel]] einen Konstruktor hinzu, so dass man das Tier-Objekt zur Katze "Pirat" mit 3 Beinen folgendermaßen instanzieren kann:
 +<code myJava>
 +Tier p = new Tier("Katze", "Pirat", 3);
 +</code>
 +
 +<HTML>
 +
 +<div class="java-online" style="height: 500px; width: 100%" data-java-online="{'withBottomPanel': true, 'id': 'KonstruktorenAufgabe2'}">
 +
 +<script type="text/plain" title="Tier2.java">
 +Tier p = new Tier("Katze", "Pirat", 3);
 +p.vorstellen();
 +
 +class Tier {
 +   String art;
 +   String name;
 +   int beinzahl;
 +
 +   // Hier fehlt der Konstruktor!
 +   
 +   void vorstellen(){
 +      println("Ich heiße " + name + " und bin ein/e " + art + " mit " + beinzahl + " Beinen.");
 +   
 +   }
 +
 +}
 +</script>
 +
 +</div>
 +</HTML>
 +[[.loesung:aufgabe2:start|Hier geht's zur Lösung!]]