Einleitung
Variablen sind in der objektorientierten Programmierung von großer Bedeutung. Durch diese können die unterschiedlichen Eigenschaften von Objekten einer Klasse beschrieben werden.
Die drei Gesichter von Variablen
Attribute, Parameter und lokale Variablen
In Java gibt es verschiedene Arten von Variablen. Sie unterscheiden sich aufgrund ihrer Sichtbarkeit und Lebensdauer.
- Attribute: Diese Variablen beschreiben Eigenschaften eines Objektes und stehen daher direkt am Anfang der Klasse außerhalb der Methoden und Konstruktoren. Sie können in allen Methoden der Klasse verwendet werden und die Variable wird bis zum Löschen des Objekts gespeichert. Zudem wird nur für Attribute die Sichtbarkeit festgelegt (public, private oder protected).
- Parameter: Parameter sind Variablen, welche du beim Aufrufen einer Methode setzen kannst. Daher kann der Parameter nur in der entsprechenden Methode verwendet werden und er wird nach dem Methodenaufruf gelöscht.
- Lokale Variable: Eine lokale Variable existiert nur innerhalb des Blocks (markiert durch { }) und kann dort für Berechnungen und Zwischenergebnisse verwendet werden.
Folgendes Beispiel verdeutlicht die unterschiedlichen Typen von Variablen:
public class MeineKlasse
{
private int einAttribut;
public int Methode1(int einParameter)
{
int eineVariable;
eineVariable = einAttribut+einParameter;
return eineVariable;
}
public void Methode2()
{
// Hier existiert nur noch das Attribut einAttribut.
// Die lokale Variable eineVariable und der Parameter
// ein Parameter kann nicht mehr verwendet werden!
}
}
Attribute und Datentypen
Informiere dich im Internet über die in Java verwendeten primitiven Datentypen und halte diese mit eine kurzen Beschreibung und einem Beispielwert in einer Tabelle fest.
| Datentyp | Beschreibung | Beispielwert |
|---|---|---|
| boolean | Wahrheitswert | true oder false |
| char | Buchstaben im Unicode | 'a', 'b', '+', usw. |
| int | ganze Zahlen | –2.147.483.648 bis 2.147.483.647 |
| long | ganze Zahlen, aber größer als int | –9.223.372.036.854.775.808 bis 9.223.372.036.854.775.807 |
| float | Kommazahlen | 1,40239846E-45f bis 3,40282347E+38f |
| double | Kommazahlen, aber größer als float | 4,94065645841246544E-324 bis 1,79769131486231570E+308 |
Deklaration und Initialisierung
- Informiere dich im Buch auf S. 82-84 über die Deklaration und Initialisierung von Variablen.
- Erläutere in eigenen Worten den Unterschied zwischen Deklaration und Initialisierung allgemein und anhand des Schubladenbeispiels
Bei der Deklaration einer Variablen wird der Bezeichner und der Datentyp der Variablen festgelegt. Bei der Initialisierung wird der Variablen zum ersten Mal ein Wert zugewiesen. Bezogen auf das Schubladenbeispiel ist die Deklaration das Aufkleben des Bezeichners auf eine passend große Schublade. Bei der Initialisierung wird zum ersten Mal ein Wert in die Schublade gelegt.
Eine Fahrzeug Klasse
Der folgende Quelltextauszug ist gegeben:
class Fahrzeug{
...
public Fahrzeug(){
String typ="VW";
String farbe="schwarz";
int baujahr = 2018;
String standort = "Erkelenz"
}
}
- Gib eine Programmzeile an, mit der ein Fahrzeug erzeugt werden kann.
- Erläutere die Auswirkungen der Attribute der Klasse Fahrzeug.
- Verbesser den Quelltext entsprechend der Anmerkungen aus der vorherigen Teilaufgabe.
- Verwende den in der vorherigen Aufgaben verbesserten Konstruktor und erzeuge drei verschiedene Fahrzeuge.
- Fahrzeug vw = new Fahrzeug();
- Die im Konstruktor deklarierten und initialisierten Variablen sind keine Attribute. Es handelt sich um lokale Variablen, deren Lebenszeit auf die Abarbeitung der Konstruktormethode Fahrzeug beschränkt ist. Somit besitzt ein Objekt der Klasse Fahrzeug überhaupt keine Attribute.
-
public class Fahrzeug { private String typ; private String farbe; private int baujahr; private String standort; public Fahrzeug (String pTyp, String pFarbe, int pBaujahr, String pStandort) { typ = pTyp; farbe = pFarbe; baujahr = pBaujahr; standort = pStandort; } } -
Zum Beispiel:
Fahrzeug vw = new Fahrzeug("VW","schwarz",2018,"Erkelenz"); Fahrzeug toyota = new Fahrzeug("Toyota","rot",1996,"Schöndorf"); Fahrzeug toyota2 = new Fahrzeug("Toyota","grün",1998,"Hilden");
Programmierung mit BlueJ
Ein neuen Editor
Nach dem Start von BlueJ erscheint eine Aufforderung zur Erstellung eines neuen Projekts. Lege dies auf deinem Stick an. Anschließend sollte folgende Oberfläche erscheinen:
Die wichtigsten Bereiche / Knöpfe:
- New Class legt eine neue Klasse an.
- Compile übersetzt alle Klassen in ausführbaren Code - sofern der Compiler keine Fehler findet. Dies geschieht auch automatisch beim Speichern des Quelltextes.
- Im Bereich für Klassen werden die einzeln Klassen deines Projekts als Rechteck aufgeführt. In späteren Projekten können das einige Klassen sein und BlueJ zeigt deren Abhängigkeiten an.
- Im Bereich für Objekte erscheinen die erstellten Objekte als rote Rechtecke. Per Rechtsklick kannst du Methoden dieser Objekte aufrufen und diese somit einfach testen.
Ein erster, kleiner Taschenrechner mit BlueJ
Grundgerüst und Addition
Alte bzw. einfache Taschenrechner funktionieren anders als die aktuellen Taschenrechner.
Es gibt eine aktuell im Speicher befindliche Zahl. Für diese können dann weitere Rechenoperationen (+,-,*,/) aufgerufen werden und die Zahl im Speicher wird mit einer weiteren Zahl verrechnet.
Solch einen einfachen Taschenrechner wollen wir mit BlueJ implementieren. Nach Erstellung einer neuen Klasse in BlueJ erscheint ein Grundgerüst einer Klasse in Java. Hier ist bereits ein Attribut x deklariert und initialisiert sowie der Konstruktor Taschenrechner und eine Beispielmethode sampleMethod implementiert worden. Im Normalfall kann man die Beispielmethode löschen.
/**
* Write a description of class Taschenrechner here.
*
* @author (your name)
* @version (a version number or a date)
*/
public class Taschenrechner
{
// instance variables - replace the example below with your own
private int x;
/**
* Constructor for objects of class Taschenrechner
*/
public Taschenrechner()
{
// initialise instance variables
x = 0;
}
/**
* An example of a method - replace this comment with your own
*
* @param y a sample parameter for a method
* @return the sum of x and y
*/
public int sampleMethod(int y)
{
// put your code here
return x + y;
}
}
Da der Taschenrechner eine Zahl speichern soll, können wir hier die Zahl x verwenden. Allerdings soll der Taschenrechner auch Kommazahlen verarbeiten, so dass int durch double ersetzt wird.
private double x;
Um die erste Zahl zu setzen, muss soll es eine Methode setzeZahl(double pZahl), welche die Zahl x durch den Wert des Parameters pZahl ersetzt:
public void setzeZahl(double pZahl){
x = pZahl;
}
Das Addieren einer weiteren Zahl y zur Zahl x im speichern soll ebenfalls durch eine neuen Methode implementiert werden: addiere(double pZahl).
public void addiere(double y){
x = x + y;
}
Eigentlich ist der Taschenrechner mit der Addition so fertig. Allerdings sieht man nichts. Damit man auch was sieht, wird noch eine Ausgabe in der Konsole ergänzt, welche immer nach der Rechnung das Ergebnis in die Konsole druckt. Dies geschieht mit dem Befehl System.out.println(...).
public void addiere(double y){
x = x + y;
System.out.println(x);
}
Insgesamt:
/**
* Ein einfacher Taschenrechner
*
* @author Tim Schellartz
* @version 10.11.2020
*/
public class Taschenrechner
{
// Zahl im Speicher
private double x;
/**
* Constructor for objects of class Taschenrechner
*/
public Taschenrechner()
{
x = 0;
}
/**
* Setzt die Zahl im Speicher auf den Wert des Parameters pZahl
*/
public void setZahl(double pZahl){
x = pZahl;
}
/**
* Addiert zur Zahl im Speicher den Wert des Parameters y
* Zudem wird das Ergebnis in der Konsole ausgegeben.
*/
public void addiere(double y){
x = x + y;
System.out.println(x);
}
}
Zum Abschluss soll der Taschenrechner getestet werden. Dazu wird durch Rechtsklick auf die Klasse Taschenrechner ein neues Objekt dieser Klasse angelegt. Im folgenden Dialog kann ein beliebiger Name für das Objekt verwendet werden.
Anschließend befindet sich ein Taschenrechner-Objekt im Bereich für Objekte. Per Rechtsklick auf das Objekt (rotes Rechteck) und anschließendem Klick auf inspect kann das Objektdiagramm aufgerufen werden. Hier werden alle Attribute und deren Werte aufgelistet. In diesem Beispiel also das Attribut x mit Wert 0.0.
Vielleicht ist es dir schon aufgefallen: Hier findest du auch die eben selbst geschriebenen Methoden. Durch einen Klick auf diese werden diese ausgeführt. Falls es Parameter gibt, wie in diesem Fall, hast du hier die Möglichkeit diese mit Werten zu belegen.
Implementation Taschenrechner
Implementiere den Taschenrechner mit folgenden Methoden:
- addiere
- subtrahiere
- multipliziere
- dividiere
Achte darauf, dein Programm häufig zu testen!
/**
* Ein einfacher Taschenrechner
*
* @author Tim Schellartz
* @version 10.11.2020
*/
public class Taschenrechner
{
// Zahl im Speicher
private double x;
/**
* Constructor for objects of class Taschenrechner
*/
public Taschenrechner()
{
x = 0;
}
/**
* Setzt die Zahl im Speicher auf den Wert des Parameters pZahl
*/
public void setZahl(double pZahl){
x = pZahl;
}
/**
* Addiert zur Zahl im Speicher den Wert des Parameters y
* Zudem wird das Ergebnis in der Konsole ausgegeben.
*/
public void addiere(double y){
x = x + y;
System.out.println(x);
}
/**
* Subtrahiert zur Zahl im Speicher den Wert des Parameters y
* Zudem wird das Ergebnis in der Konsole ausgegeben.
*/
public void subtrahiere(double y){
x = x - y;
System.out.println(x);
}
/**
* Multipliziert zur Zahl im Speicher den Wert des Parameters y
* Zudem wird das Ergebnis in der Konsole ausgegeben.
*/
public void multipliziere(double y){
x = x * y;
System.out.println(x);
}
/**
* Dividiert die Zahl im Speicher durch den Wert des Parameters y
* Zudem wird das Ergebnis in der Konsole ausgegeben.
*/
public void dividiere(double y){
x = x / y;
System.out.println(x);
}
}
Erweiterung Taschenrechner
Verwende den Taschenrechner aus der vorherigen Aufgabe und erweitere diesen um folgende Funktionen (hier brauchst du Schleifen!):
hoch(int n)Die Zahl im Speicher soll n mal mit sich selbst multipliziert werden.-
quadratwurzel()Berechne \(\sqrt{x}\). Verwende dazu folgenden Pseudocode:Pseudocode näherunsweises Wurzelziehen (Heron Verfahren)- Initialisiere wurzel mit 1
- Wiederhole 10 mal:
- Ersetze wurzel mit dem Mittelwert aus wurzel und x/wurzel
- wurzel enthält nur den Näherungswert
-
Bonus: In der vorherigen Aufgabe hast du das Heron Verfahren implementiert. Allerdings ist die feste Anzahl Wiederholungen nicht gut. Zum einen kann die Näherung bei großen Eingabezahlen zu ungenau sein, zum anderen kann sie bei manchmal zu viele Schritte machen um eine gewisse Genauigkeit zu erreichen.
Verändere den Code des so, dass er die Genauigkeit als Abbruchbedingung verwendet, also wann verändert sich das vorherige zum aktuellen Ergebnis nur noch um zum Beispiel < 0,001.
Beispiel wurzel()
/**
* Berechnet x hoch n
* Zudem wird das Ergebnis in der Konsole ausgegeben.
*/
public void hoch(int n){
double potenz = 1;
for(int i=0;i < n;i++){
potenz = potenz*x;
}
x=potenz;
System.out.println(x);
}
/**
* Berechnet näherungsweise die Wurzel von x.
* Zudem wird das Ergebnis in der Konsole ausgegeben.
*/
public void wurzel(){
double wurzel = 1;
if(x > 0){
for(int i=0;i < 10;i++){
wurzel = (wurzel+x/wurzel)/2.0;
}
}
x=wurzel;
System.out.println(x);
}
/**
* Berechnet die Wurzel von x mit dem Heron Verfahren und einem Genauigkeitswert von 0,001.
* Zudem wird das Ergebnis in der Konsole ausgegeben.
*/
public void wurzel2(){
double wurzel = 1.0;
double old = -1.0;
if(x>0){
while(Math.abs(wurzel-old)>0.001){
old = wurzel;
wurzel = (wurzel+x/wurzel)/2.0;
}
}
x=wurzel;
System.out.println(x);
}
Funktionen mit Rückgabe (return)
Häufig sollen Funktionen in Java nicht nur etwas machen, sondern einen Wert zurückliefern. Ein einfaches Beispiel ist die Funktion max(int a, int b), welche das Maximum der Zahlen a und b zurückliefert.
public int max(int a, int b){
if(a>b){
return a;
}
return b;
}
Das diese Funktion einen Wert, genauer eine ganze Zahl zurückliefert, wird schon in der Methodendeklaration
public int max(int a, int b)
deutlich. Funktionen mit Rückgabetyp in der Methodendeklaration müssen einen Wert zurückgegeben, also immer return ...; enthalten. Ein praktischer Tipp: Die Zeile mit return ...; beendet die Methode, daher kann das Beispiel ohne else implementiert werden.
Weitere Übungen
In folgenden Übungen werden gewisse Berechnungen angestellt und des Ergebnis als return Wert zurückgegeben. Der Wert der Variable x des Taschenrechners wird nicht geändert.
Implementiere folgende Methoden:
fakultaet(int n)Berechnet die Fakultät der Zahl n. Beispiel fakultaet()sum(int n)Berechnet die Summe der Zahlen von 1 bis n. Beispiel sum()
/**
* Berechnet die fakultät von n
*/
public int fakultaet(int n){
int erg = 1;
for(int i=2;i<=n;i++){
erg *= i;
}
return erg;
}
/**
* Berechnet die Summe der Zahlen von 1 bis n
*/
public int sum(int n){
int erg = 0;
for(int i=1;i<=n;i++){
erg += i;
}
return erg;
}
Größter gemeinsamer Teiler
In vielen mathematischen Anwendungen spielt der größte gemeinsamer Teiler (kurz ggt) zweier Zahlen einer Rolle. Zum Beispiel beim Kürzen von Brüchen.
Unter dem ggt zweier Zahlen a und b versteht man die größte natürliche Zahl die sowohl durch a, als auch durch b ohne Rest teilbar ist.
Für die Berechnung gibt es folgenden Pseudocode:
Pseudocode größter gemeinsamer Teiler
ggt(a,b):
wenn a = 0 dann
Ergebnis = b
sonst
solange b ungleich 0
wenn a > b dann
ersetze a durch a-b
sonst
ersetze b durch b-a
ende wenn
ende solange
Ergebnis = a
ende sonst
Implementiere den Algorithmus zur Berechnung des größten gemeinsamen Teilers.
/**
* Berechnet den größten gemeinsamen Teiler von a und b
*/
public int ggt(int a, int b){
if(a==0){
return b;
}else{
while(b!=0){
if(a>b){
a = a-b;
}else{
b = b-a;
}
}
return a;
}
}
Eingaben einlesen mit der Scanner-Klasse
Scanner Klasse
Das dein toller Taschenrechner nur über die BlueJ-Oberfläche bedient werden kann hat zwei Nachteile: Zum einen hat nicht jeder potenzielle Benutzer BlueJ installiert und zum anderen ist Bedingung per Maus umständlich. Abhilfe schafft das Einlesen von Befehlen und Werten über die Konsole.
Scanner Klasse
Die Klasse Scanner kann von dir verwendet werden um Text innerhalb der Konsole einzulesen. Dazu musst du 3 Schritte durchführen:
- Importiere die Klasse aus den Java-Paketen. Schreibe dazu
import java.util.Scanner;ganz an den Anfang der Datei, noch außerhalb der Klassendefinition. - Da man meist mehrere Dinge aus der Konsole auslesen möchte bietet es sich an den Scanner innerhalb Klasse als Attribut mit
Scanner sc = new Scanner(System.in)zu deklarieren und zu initialisieren. - Anschließend kannst du innerhalb dieser Klasse den Scanner mittels
sc.nextLine()eine Zeile einlesen lassen. Dies liefert einen String als Rückgabewert.
Beispiel:
import java.util.Scanner;
/**
* Eine einfache Klasse mit Scanner
*/
public class EineKlasse{
Scanner sc = new Scanner(System.in);
/**
* Liest den Namen einer Person ein und begrüßt diese
*/
public void eineMethode(){
String name = sc.nextLine();
System.out.println("Hallo " + name);
}
}
Implementation mit Scanner
- Erstelle eine weitere Klasse
Main. In dieser Klasse legst du ein Attribut Taschenrechner tr und ein Scanner sc an. (Deklaration + Initialisierung) - Kopiere folgenden Code in die Klasse Main und beschreibe was dieser Codeabschnitt macht.
public void starteRechner(){ String eingabe = ""; while(!eingabe.equalsIgnoreCase("ende")){ eingabe = sc.nextLine(); String operator = eingabe.substring(0, 1); double zahl = Double.parseDouble(eingabe.substring(1)); if(operator.equals("+")){ tr.addiere(zahl); }else { System.out.println("Operator nicht enthalten. Verwenden Sie:"); System.out.println("+"); System.out.println("Beispiel für 'Addiere 565': +565"); } } } - Erweitere die Methode starteRechner um weitere Operatoren.
1. und 3. -> siehe Code unten. Zu 2.: Eine Eingabe wird eingelesen und das erste Zeichen (eingabe.substring(0,1) liefert nur das erste Zeichen) wird als Operator verstanden und in als lokale Variable operator gespeichert. Der Rest nach dem ersten Zeichen wird durch eingabe.substring(1) erreicht. Dies wird dann, falls möglich, in eine Kommazahl umgewandelt (Double.parseDouble()und als Variable zahl gespeichert. Dann wird für den + Operator die bereits in der Klasse Taschenrechner implementierte Methode addiere mit der Zahl in der lokalen Variablen zahl aufgerufen. Ist der Operator nicht sinnvoll, so wird eine Fehlermeldung angezeigt.
import java.util.Scanner;
/**
* Write a description of class Main here.
*
* @author Tim Schellartz
* @version 18.11.2020
*/
public class Main
{
Taschenrechner tr;
Scanner sc;
public Main(){
tr = new Taschenrechner();
sc = new Scanner(System.in);
}
public void starteRechner(){
String eingabe = "";
while(!eingabe.equalsIgnoreCase("ende")){
eingabe = sc.nextLine();
String operator = eingabe.substring(0, 1);
double zahl = Double.parseDouble(eingabe.substring(1));
if(operator.equals("+")){
tr.addiere(zahl);
}else if(operator.equals("-")){
tr.subtrahiere(zahl);
}else if(operator.equals("*")){
tr.multipliziere(zahl);
}else if(operator.equals("/")){
tr.dividiere(zahl);
}else {
System.out.println("Operator nicht enthalten. Verwenden Sie:");
System.out.println("+,-,*,/");
System.out.println("Beispiel für 'Addiere 565': +565");
}
}
}
}
Exkurs: Gefährliche Fehler
Meist sind Softwarefehler vor allem ärgerlich. Manchmal können die Folgen von fehlerhafter Programmierung allerdings sehr teuer oder sogar tödlich sein. Die Webseite listet einige Beispiele auf. Auch das folgende Video zeigt ein teures Beispiel.