Programm in main Methode testen

jaybe

Mitglied
Ich hänge gerade bei was sehr einfachem fest. Ihr wisst bestimmt sofort ne Lösung.
Habe folgendes einfaches Programm geschrieben:

Java:
public class FlussQuerschnitt {

  //Attribute

  private double b;
  private double h;
  private double n;
  
  //Allgemeiner Konstruktor
  
  public FlussQuerschnitt(double b, double n){
    this.b=b;
    this.n=n;
    this.h=0.0;
  }
  
  //Methode "setWasserstand"
  
  public void setWasserstand(double h){
    if (h>4) {
      h=4;
    } else{
      h=h;
    }
    
    if (h<0.5) {
      h=0.5;
    } else {
      h=h;
    }
  }
  
  //Methode "readWasserstand"
  
  public void readWasserstand(){
    System.out.println("Geben sie den Wasserstand ein.");
    do {
      h=Keyboard.readDouble();
    } while (h<4 && h>0.5);
  }
  
  //Methode "getAbflussQuerschnitt"
  
  public double getAbflussQuerschnitt(){
    double A=h*(b+n*h);
    return A;
  }

Jetzt will ich das alles testen. Dazu kann ich doch entweder eine Neue Klasse erstellen oder in die bestehende Klasse die Main Methode einbauen. Meine Variante sieht so aus:

Java:
// Main Mehtode um die das Programm zu testen
  
  public static void main(String[] args) {
    FlussQuerschnitt meinFQ = new FlussQuerschnitt();
  }

Ich will einen neuen Flussquerschnitt erstellen, aber der Java Editor zeigt mir immer den Fehler, dass er den Konstruktor nicht finden kann. Habt ihr nen Tipp. Stehe gerade auf dem Schlauch.

Vielen Dank schon einmal 😉
 
Mein Tipp ist, das zu betrachten, was der Compiler einem sagt 😉

Es gibt keinen Konstruktor
Code:
FlussQuerschnitt()
, nur einen
Code:
FlussQuerschnitt(double, double)
.
 
Vielen Dank für die schnelle Antwort. Auf die Idee bin ich eben auch gekommen.
Habe aber folgendes geschrieben:
Code:
FlussQuerschnitt(double b, double n)
.
Damit hat es nicht funktioniert und leider auch nicht mit deiner Idee. Der erwartet
Code:
.class
Wieso ?
 
Sobald du einen Konstruktor mit Parameter definierst, existiert der Standardkonstruktor in deinem Fall
Code:
FlussQuerschnitt()
nicht mehr, es sei dem du definierst ihn auch. Defeinierst du gar keinen Konstruktor, so ist der standardKonstruktor
Code:
FlussQuerschnitt()
automatisch vorhanden.
 
schreibe in main:

Java:
public static void main(String[] args) {
    FlussQuerschnitt meinFQ = new FlussQuerschnitt(3.0, 4.2);
  }
 
Deine Methode setWasserstand ist übrigens kritisch, da du zweimal h verwenden willst, aber in Wirklichkeit immer das selbe h ansprichst. Somit hat
Code:
h=h
keinen Effekt und
Code:
h=4
würde sich auch nur auf das h innerhalb der Methode beziehen. Mein Tipp, nutz da doch unterschiedliche Variablennamen, am besten sprechende Namen wie hoehe und hoeheNeu oder so, dann weißt du wenigstens was gemeint ist.
 
Die Methode setWasserstand soll folgendes tun:

Das Attribut zur Speicherung des Wasserstands soll durch die öffentliche Methode
Code:
setWasserstand(h:double):void
gesetzt werden können.
Mit einer if...else if...else-Struktur soll sichergestellt werden, dass der Wasserstand maximal zu 4.0gesetzt wird, falls größere Werte übergeben werden und minimal zu 0.5, falls kleinere Werte übergeben werden


Und was meinst du jetzt genau habe ich falschgemacht ? :bahnhof:

//edit//

Ok. Irgendwie will das Programm nicht so ganz. Vll. könntet ihr mir noch ein wenig helfen.
Die Methode
Code:
readWasserstand
ist glaube ich falsch.
Sie soll solange Werte einlesen, bis man einen Wert eingibt,
der zwischen 0,5 und 4 liegt. Aber meine Abbruchbedingung scheint falsch zu sein.

Des weiteren will ich danach dann die Methode
Code:
setWasserstand
aufrufen, mit
Code:
meinFQ.setWasserstand(double h)
. Aber das klappt leider nicht.

Dabei ist das doch eigentlich so einfach 😳
 
Zuletzt bearbeitet:
Und was meinst du jetzt genau habe ich falschgemacht ? :bahnhof:

Du hast nicht die if-else-Bedingung falsch umgsetzt, sondern gehst falsch mit den Variablen um. Du schreibst das hier:

Java:
if (h>4) {
  h=4;
} else{
  h=h;
}

Wobei
Code:
h=h
zum Beispiel garnichts tut! Richtig wäre:

Java:
if (h>4) {
  this.h=4;
} else{
  this.h=h;
}

Verstehst du den Unterschied? Auch deshalb ist es wichtig, dass man unterschiedliche Variablennamen nutzt, die am besten auch möglichst etwas aussagen, damit solche Fehler nicht passieren.

Was deine Methode readWasserstand() macht, kann ich eigentlich nicht sagen, weil ich nicht weiß, was du Klasse Keyboard sein soll.
 
So richtig verstehe ich noch nicht den Unterschied. Wieso muss man jetzt "this" benutzen ?
Meinst du ich hätte
Code:
this.h=hoehe
schreiben sollen ?

Mit der Klasse Keyboard liest man die Variablen von der Tastatur ein.
Damit wird der Benutzer aufgefordert einen Wert für "h" einzugeben.
 
Meinst du ich hätte
Code:
this.h=hoehe
schreiben sollen ?

Zum Beispiel könnte man es so machen:

Java:
	private double wasserstand;

	public void setWasserstand(double hoehe) {
		if (hoehe > 4) {
			wasserstand = 4;
		} else {
			wasserstand = hoehe;
		}

		if (hoehe < 0.5) {
			wasserstand = 0.5;
		} else {
			wasserstand = hoehe;
		}
	}
 
Nochmal zum Verständnis:

Also ist das "this" nur optional.
Mit
Code:
this.h
greife ich dann auf den Konstruktor zurück.
Und durch das
Code:
double hoehe
in
Code:
public void setWasserstand(double hoehe)
wird eine neue Variable definiert.

Stimmt das ?

Ich habe zudem Probleme mit der Abbruchbedingung in folgender Schleife:

Java:
public void readWasserstand(){

    do {
      System.out.println("Geben sie den Wasserstand ein. Er muss zwischen 0.5 und 4 liegen");
      h=Keyboard.readDouble();
    } while (h>4 && h<0.5);
  }

Das mit dem
Code:
while (h>4 && h<0.5)
klappt noch nicht.
 
Zuletzt bearbeitet:
Nein, this is in dem Fall nicht optional.

Du hast:
Java:
public class FlussQuerschnitt {
 
  //Attribute
 
  private double b;
  private double h;
  private double n;
  [...]
public void setWasserstand(double h){
    if (h>4) { // was ist hier "h"? Immer der Parameter der Methode...
      h=4; // was ist hier "h"? Immer der Parameter der Methode...
    } else{
      h=h; // was ist hier "h"? Immer der Parameter der Methode...
    }

Das heißt einmal ist h die Membervariable von deinem Object FlussQuerschnitt und einmal Parameter der Methode. Wenn du in der Methode dich auf "h" beziehst nimmt er den Parameter. Mit "this.h" wird die Membervariablen adressiert.

Wenn du es jetzt umbenennst:
Java:
public class FlussQuerschnitt {
 
  //Attribute
 
  private double b;
  private double h;
  private double n;
  [...]
public void setWasserstand(double hoehe){
    if (hoehe>4) {
      h = 4;
    } else{
      h = hoehe;
    }
ist klar was gemeint ist. Wenn du bei den gleichen Namen bleiben willst musst du halt "this" verwenden.

Java:
public class FlussQuerschnitt {
 
  //Attribute
 
  private double b;
  private double h;
  private double n;
  [...]
public void setWasserstand(double h){
    if (h>4) {
      this.h = 4;
    } else{
      this.h = h; // this.h = h als attribut des Objects, h ohne this Parameter
    }
 
Also ist das "this" nur optional.

Wenn der Name hinter dem this eindeutig währe, ja, aber das ist er bei dir nicht. Es gibt einen Parameter h und eine Variable h, also ist this zwingend.

Egal was irgendwo steht: NIEMALS denselben Namen zweimal nutzen.
(Ja ich weiss - jetzt kommen wieder die militanten Vertreter irgend welcher skurillen Codeguidelines - das wird meine Meinung niht ändern!)
Zweimal hält besser:
NIEMALS denselben Namen zweimal benutzen.

Du weisst jetzt hoffentlich warum - das viel besser ist als das weiter unten

Java:
public void setWasserstand(double hoehe) {
	if (hoehe>4) {
		h = 4;
	} else {
		h = hoehe;
	}

Java:
public void setWasserstand(double h) {
	if (h>4) {
// Da geschieht nichts schalues - dem Parameter h wird der Wert 4 zugewiesen
		h=4;
	} else {
// Hier passiert der Fehler! Du weisst dem parameter h den wert zuden er selbst schon hat!
		h=h;
	}
}


Mit
Code:
this.h
greife ich dann auf den Konstruktor zurück.
Nein! this hat nichts mit dem Konstruktor zu tun. Damit greifst du auf die Variable h in deinem Objekt zu.

Und durch das
Code:
double hoehe
in
Code:
public void setWasserstand(double hoehe)
wird eine neue Variable definiert.

Nein!
Code:
double hoehe
ist ein Parameter, keine Variable
 
Zuletzt bearbeitet:
Egal was irgendwo steht: NIEMALS denselben Namen zweimal nutzen.
(Ja ich weiss - jetzt kommen wieder die militanten Vertreter irgend welcher skurillen Codeguidelines - that doesn't touch my soul!)¨Zweil mal hält besser.
NIEMALS denselben Namen zweimal benutzen.

Naja... finde ich besser als irgendwelche Underscore oder "p" Varianten:
Java:
class A{
  String _myString;
  public void setString(String myString){
    _myString = myString;
  }
}

class B{
  String myString;
  public void setString(String pMyString){
    myString = pMyString;
  }
}

class C{
  String myString;
  public void setString(String myString){
    this.myString = myString;
  }
}

Letzlich eine Geschmackssache. Auser bei sehr einfachen Fällen wie Settern oder so vermeide ich es aber auch.
 
Ich sagte militant - stur und unbelehrbar passen zusätzlich auch noch!

Wir haben eben ein Paradebeispiel vor uns was für Fehler passieren nur weil man dem Compiler keine Möglichkeit gibt zu helfen und du behauptest so etwas!

Wenn java wenigstens die Parameter alle implizit und unveränderbar als final definieren würde - aber nein - es bietet alle Mögichkeiten Blödsinn zu bauen.

Jeder Name MUSS eindeutig sein - und wenn du mich fragst ist Gross- und Kleinschreibung KEIN Unterscheidungsmerkmal sondern nur eine Lesehilfe.

Weiteres wird man von mir in diesem Thread nicht mehr lesen.
 
Das mit dem
Code:
while (h>4 && h<0.5)
klappt noch nicht.
Na, dann nenn mir mal einen Wert der gleichzeitig größer als 4 und kleiner als 0.5 ist. 😉

Außerdem immer schön dieselben Variablennamen wählen, zur Unterscheidung haben wir schließlich [c]this[/c]. 😉
Um solche Fehler zu vermeiden, kann man entweder auf Compiler-Warnings achten oder ein [c]final[/c] vor den Parameter setzen. Das verhindert, dass du ihm einen neuen Wert zuweist.
 
Na, dann nenn mir mal einen Wert der gleichzeitig größer als 4 und kleiner als 0.5 ist. 😉

Ja das habe ich so geschrieben, da er anders gar nichts macht.
Also rein logisch müsste es doch so aussehen:
Code:
while (this.h<4 && this.h>0.5)
Aber wenn ich dann das Programm starte und z.B. die "5" eingebe reicht ihm das und er unterbricht die Schleife. Wieso ?
 
Weil 5 nicht kleiner als 4 ist.

In dem Kontext ist es übrigens egal, ob du das [c]this[/c] setzt oder nicht, schließlich gibt es dort nur eine Variable h.
Du solltest dies aber in der Tat über eine lokale Variable machen und erst am Ende den Wert zuweisen:
Java:
public void readWasserstand(){
    double h;
    do {
        System.out.println("Geben Sie den Wasserstand ein. Er muss zwischen 0.5 und 4 liegen.");
        h = Keyboard.readDouble();
    } while (/* hier nochmal Bedingung überdenken */);
    this.h = h;
}
 
Zuletzt bearbeitet:
Ich sagte militant - stur und unbelehrbar passen zusätzlich auch noch!

Mein Güte... Du hast eine Art... Aber das fällt ja nicht zum ersten Mal auf.

Meine Erfahrung zeigt, dass leider viele die Bedeutung von dem Keyword "this" einfach nicht ausreichend kennen. Da ist es keine Hilfe zu sagen: "Och, benutz es nicht sondern benenn einfach alles eindeutig!". Je früher man sich damit auseinandersetzt und es auch wirklich versteht, desto leichter hat man es später. Wird ja auch in anderen Zusammenhängen gebraucht, z.B. für sowas:
Java:
public class A {

	public static void main(String[] args) {
		A a = new A();
		a.doSomething();
		B  b = new B();
		b.doSomething();
		b.doSomethingElse();
	}

	public void doSomething(){
		System.out.println("A");
	}
	
}

class B extends A{
	
	public void doSomething(){
		System.out.println("B");
	}
	
	public void doSomethingElse(){
		super.doSomething();
		this.doSomething();
	}
}

Wir haben eben ein Paradebeispiel vor uns was für Fehler passieren nur weil man dem Compiler keine Möglichkeit gibt zu helfen und du behauptest so etwas!

Wenn java wenigstens die Parameter alle implizit und unveränderbar als final definieren würde - aber nein - es bietet alle Mögichkeiten Blödsinn zu bauen.

Das liegt nicht daran das Java einem die Möglichkeit bietet jede Menge Blödsinn zu bauen - sondern daran das man beim Lernen der Sprache halt nicht einfach mal soetwas aussen vor lassen sollte. Ich kann in anderen Sprache noch deutlich mehr Blödsinn machen...

Eine moderne IDE weißt da übrigens grafisch drauf hin: Gelb unterstrichen: "h = h" => "the assignment to variable h has no effect"

Jeder Name MUSS eindeutig sein - und wenn du mich fragst ist Gross- und Kleinschreibung KEIN Unterscheidungsmerkmal sondern nur eine Lesehilfe.

Wenn man dich fragt... fragt sich wer sich hier militant, stur und unbelehrbar zeigt 😉

Weiteres wird man von mir in diesem Thread nicht mehr lesen.

Na, da bin ich aber gespannt.
 
Zuletzt bearbeitet von einem Moderator:
Aber wenn ich noch eine lokale Variable ins Spiel bringe wird das durcheinander doch noch größer. Ich will ja, dass der eingegebene Wert das "h" ist, was ich ganz am Anfang der Klasse deklariert habe. Jetzt habe ich doch noch ein zweites "h" erstellt. Ist dass nicht verwirrend ?!😱

Und die While-Schleife wir doch solange durchgeführt bis die Bedingung war ist. Oder irre ich mich da ?!
 
Aber wenn ich noch eine lokale Variable ins Spiel bringe wird das durcheinander doch noch größer. Ich will ja, dass der eingegebene Wert das "h" ist, was ich ganz am Anfang der Klasse deklariert habe. Jetzt habe ich doch noch ein zweites "h" erstellt. Ist dass nicht verwirrend ?!😱
Kommt auf den jeweiligen Menschen an, was er als Durcheinander empfindet. 😉
So, wie du es momentan machst, wird der Wert schon der Instanzvariabe h zugewiesen, bevor du überprüfst, ob er überhaupt valide ist. Daher herrscht dann innerhalb dieser while-Schleife eine Inkonsistenz, was nicht schön ist.
Am besten liest du den eingegebenen Wert erst in eine lokale Variable ein, validierst und weist dann der Instanzvariable zu. Wie du letztendlich die lokale Variable nennst, bleibt dir überlassen.

Und die While-Schleife wir doch solange durchgeführt bis die Bedingung war ist. Oder irre ich mich da ?!
Ja, du irrst dich. Einfach nochmal die Definition nachlesen (und vielleicht mal laut vor sich hin sagen: "TU (do) das WÄHREND (while) dies gilt").

@fassy: In deinem Beispiel braucht man das [c]this[/c] aber nicht – und ich würds an dieser Stelle auch nicht verwenden. 🙂
 
Zuletzt bearbeitet:
Und ich habe die ganze Zeit "TU das "Solange bis" das gilt im Kopf 🙄

Müsste dann so aussehen:
Code:
while (this.h>4 || this.h<0.5)
Wie kann man die Senkrechten Striche mit der Tastaur machen? Habe sie nur kopiert.
 
Zuletzt bearbeitet:
So einen Ausdruck gibts z. B. in Visual Basic:
Code:
Do
    ' Code
Loop Until {Boolean}
In Java jedoch nicht (direkt). Lässt sich aber so leicht nachbilden:
Java:
do {
    // Code
} while (!{boolean});

Mit einem logischen Oder bist du hier aber wirklich ganz gut aufgehoben.
Den Pipe (senkrechten Strich) findest du unten links (zwischen Shift und y), erreichbar über Alt Gr.
 
Aha. Danke :toll:

Nochmal ne andere Frage.
Mit "super" greift man ja auf Variablen aus anderen Klassen zurück. Meine Frage:

Ist folgendes das Gleiche:
Code:
super.x=x;
und
Code:
super(x);
???
 
Ohgott, nein.

super(x) kannst du nur im Konstruktor machen, da würdest du den "nächsthöheren" Konstruktor mit dem Parameter x aufrufen. In einer Methode method() würde ein super-Aufruf so aussehen: super.method();

super.x=x hingegen würde der Variable x aus der Oberklasse den Wert von x zuweisen.
 
Es ging nämlich um folgenden "Allgemeinen Konstruktor":

Musterlösung sagt:

Java:
public Bus(int fahrzeugnummer, int sitzplaetze){
super(fahrzeugnummer);
this.sitzplaetze = sitzplaetze;
}

Meine erste Überlegung war:

Java:
public Bus(int fahrzeugnummer, int sitzplaetze){
super.fahrzeugnummer=fahrzeugnummer;
this.sitzplaetze = sitzplaetze;
}

So ganz bin ich leider noch nicht durchgestiegen, wo jetzt genau der Unterschied liegt :rtfm:
 
Das eine mal rufst du den Konstruktor der Oberklasse auf, das andere mal weist du dem Attribut das aus der Oberklasse geerbt wird einen Wert zu.

Probier mal das hier:
Java:
public class Fahrzeug {
    int fahrzeugnummer;
    int sitzplaetze;
    
    
	public static void main(String[] args) {
		
		Bus  b = new Bus(123,34);
		System.out.println(b);
		
		Auto a = new Auto(234,24);
		System.out.println(a);
		
	}

	public Fahrzeug(){
		
	}
	
	public Fahrzeug(int fahrzeugnummer){
		this.fahrzeugnummer = fahrzeugnummer;
		System.out.println("Called Constructor");
	}
	
    public String toString(){
    	return fahrzeugnummer + " " +sitzplaetze;
    }
	
}

class Auto extends Fahrzeug {
	public Auto(int fahrzeugnummer, int sitzplaetze){
		super(fahrzeugnummer); // ruft den Constructor von Fahrzeug auf
		this.sitzplaetze = sitzplaetze;
		}
}

class Bus extends Fahrzeug{

	public Bus(int fahrzeugnummer, int sitzplaetze){
		super.fahrzeugnummer=fahrzeugnummer; // weist dem Attribute das aus der Klasse Fahrzeug geerbt wird einen Wert zu
		this.sitzplaetze = sitzplaetze;
		}
	
}
 
Es kann sein, dass letztendlich dasselbe rauskommt, semantisch ists aber auf jeden Fall verschieden.
Beim obigen Code-Beispiel kommen dieselben Werte für die beiden Fahrzeuge raus + beim expliziten Konstruktoraufruf die Konsolenausgabe. Beim Konstruktoraufruf wird übrigens als Allererstes über die Superklassenhierarchie durchdeligiert, weil erst mal alle Superklassen-Konstruktoren aufgerufen werden müssen. Deutlich wird dies, wenn du in beide Fahrzeug-Konstruktoren Konsolenausgaben reinschreibst:
[JAVA=17] public Fahrzeug() {
System.out.println("Implicit constructor call");
}[/code]
[JAVA=21] public Fahrzeug(int fahrzeugnummer) {
this.fahrzeugnummer = fahrzeugnummer;
System.out.println("Explicit constructor call");
}[/code]
Du siehst hieran, dass beim Bus-Konstruktor der Fahrzeug-Konstruktor ohne Parameter automatisch aufgerufen wird, während du beim Auto-Konstruktor den Fahrzeug-Konstruktor mit Parameter aufrufst.

Es ist auch gut möglich, dass deine erste Überlegung gar nicht erst kompiliert. Dein Konstruktor versucht nämlich implizit, über super() den parameterlosen Fahrzeug-Konstruktor aufzurufen, den es nicht gibt, wenn ein anderer Konstruktor (also mit einem int-Parameter) erstellt wird.

Wenn du aus fassys Code also Zeilen 17-19 auskommentierst, kompiliert das Beispiel nicht mehr mit der Fehlermeldung "Implicit super constructor Fahrzeug() is undefined. Must explicitly invoke another constructor".

Der Unterschied zwischen beiden Ansätzen wird auch deutlich, wenn der Super-Konstruktor anders aussieht, etwa so:
[JAVA=21] public Fahrzeug(int sitzplaetze) {
this.sitzplaetze = sitzplaetze;
}[/code]

Über den Aufruf
Code:
super(fahrzeugnummer);
würdest du dann nicht die Fahrzeugnummer, sondern die Anzahl der Sitzplätze ändern.

Edit: Mal wieder zu spät dran. :joke:
 

Zurück
Oben