isEmpty selbst realisieren

Status
Nicht offen für weitere Antworten.
G

Guest

Gast
Hallo,

also ich sitze an einer Aufgabe, die ich eigentlich ganz gut verstehe und fast komplett umgesetzt habe.
Jedoch verstehe ich einfach nicht, wie ich Aufgabenteil b) umsetzen kann.
Dort soll ja überprüft werden, ob Elemente im Intervall sind (Intervall ix = new Intervall(7,12)) oder eben nicht (Intervall ix = new Intervall()).
Unter c) soll das ja mit dem letzten Konstruktor erreicht werden.
Meine Idee war sowas wie:
Code:
if (lower==null & upper==null)
   isEmpty=true;

Aber wie ich mich auch drehe und wende, das funzt nicht :cry:

Hier mal die Aufgabe:





Danke schon mal im Voraus!!!

P.S.: Ich denke nicht, dass wir die javaeigene Methode "isEmpty" nehmen sollen.
 

Tobias

Top Contributor
Na, so ganz ohne Code kann man da nicht viel zu sagen, aber du mußt überprüfen, ob die untere Grenze (lower) größer oder gleich (>=) der obern Grenze (upper) ist.

mpG
Tobias
 

rumpi

Mitglied
Ist aber nur eine frühe Beta ;)
Interessant sind also Zeile 16-18.
Code:
public class Test {
	
	private int lower, upper;
	private boolean isEmpty;
	
	public Test(){
	}
	public Test(int lower){
		this.lower = lower;
		this.upper = lower;
	}
	public Test(int lower, int upper){
		this.lower = lower;
		this.upper = upper;
	}
	public Test(int lower, int upper, boolean isEmpty){
		if ()
			isEmpty=true;
	}
	public int getLower(){
		return this.lower;
	}
	public int getUpper(){
		return this.upper;
	}
	public void setLower(int lower){
		this.lower = lower;
	}
	public void setUpper(int upper){
		this.upper = upper;
	}
	public String toString(){
		return "[" + lower + ".." + upper + "]";
	}
	public int length(){
		if (lower > upper)
			return 0;
		else
			return getUpper()-getLower()+1;
	}
	public boolean contains(int t){
		if (t>=getLower() & t<=getUpper())
			return true;		
		else
			return false;
	}
	public boolean contains(Test t){
		if (t.lower>=this.lower && t.upper<=this.upper)
			return true;
		else
			return false;		
	}
	public boolean disjoint(Test t){
		if (t.lower>this.upper | t.upper<this.lower)
			return true;
		else
			return false;
	}
	public Test schnitt(Test t){
		if (this.contains(t.lower)==true & this.contains(t.upper)==true)
			return t;
		else if (t.contains(this.lower)==true & t.contains(this.upper)==true)
			return this;
		else if (this.contains(t.lower)==false & this.contains(t.upper)==true){
			t.lower=this.lower;
			return t;			
		}
		else if (this.contains(t.lower)==true & this.contains(t.upper)==false){
			t.upper=this.upper;
			return t;
		}
		else if (t.contains(this.lower)==false & t.contains(this.upper)==true){
			this.lower=t.lower;
			return this;			
		}
		else if (t.contains(this.lower)==true & t.contains(this.upper)==false){
			this.upper=t.upper;
			return this;
		}
		else
			return new Test();
	}
	public static void main (String[] args){
		Test t1 = new Test();
		Test t2 = new Test(7,10);
		Test t3 = new Test(7,5);
		Test t4 = new Test(7,9);
		Test t5 = new Test(8,10);
		Test t6 = new Test(7);
		System.out.println(t1.length());
	}

}
 

Tobias

Top Contributor
Da es sich ja um eine Hausaufgabe handelt, mag ich dir jetzt nicht den Spaß verderben, indem ich hier Code poste. Aber bei dieser Klasse ist mein oben gegebener Ansatz schon richtig: Ist die untere Grenze größer oder gleich der oberen, ist das Intervall leer. Allerdings ignorierst du in den Zeilen 16-18 im Konstruktor die Tatsache, dass der Konstruktor die Information, ob das Intervall leer ist oder nicht, bereits in Form des letzten Parameters übergeben bekommt. Du musst hier also die entsprechende Prüfung anhand der gegebenen Grenzen durchführen und wenn das Ergebnis dieser Prüfung und der gegebene letzte Parameter nicht übereinstimmen, eine Exception auslösen!
 

rumpi

Mitglied
Ich lege doch in 84-89 Intervalle an. Was ich jetzt nicht verstehe, warum es einmal einen Konstruktur lower, upper gibt und einmal lower,upper,isEmpty. Reicht nicht letzterer? Hat isEmpty ne besondere Bedeutung, oder könnte da auch "leer" stehen? Ich stehe voll auf der Leitung. Wieso bekommt der Konstruktor mit dem letzten Parameter schon mit, ob das Intervall leer ist oder nicht? Solange der Konstruktor nicht weiß, was er mit dem true/false anfangen soll, hat isEmpty doch den Defaultwert false.
 

Tobias

Top Contributor
Der letzte Konstruktor ist in der Tat ziemlich bescheuert, weil isEmpty eine von upper und lower abhängige Variable ist. Sprich dieser Konstruktor zwingt den Benutzer dazu, sich unnötige Gedanken über das Intervall zu machen. In "normalem" Code würde man so einen Konstruktor einfach weglassen, weil er keinen Mehrwert bringt und obendrein noch neue Fehlermöglichkeiten einführt. In diesem Fall ist dieser Konstruktor wohl dem didaktischen Gedanken geschuldet, aka "Lassen wir unsere Studenten doch mal eine Exception auslösen".

EDIT: Noch was, was ich bisher übersehen habe: Du initialisierst in den beiden anderen Konstruktoren isEmpty gar nicht. Ebenfalls Teil der Übung dürfte Constructor-Chaining sein, sprich der Aufruf eines anderen Konstruktors mit weiteren (berechneten / festgelegten) Parametern im Konstruktor.
 

rumpi

Mitglied
Das ist die erste objektorientierte Aufgabe...
Jetzt kommst du auch noch mit Chaining :D . Funktioniert das mit extends??
Ich denk jetzt noch mal richtig drüber nach. Atm blick ich gar nichts mehr...
 

rumpi

Mitglied
Code:
public Test(int lower, int upper, boolean isEmpty){
		this(lower, upper);
		this.isEmpty = isEmpty;
		if (lower>=upper)
			isEmpty=true;
			
	}
Ich rufe die beiden Methoden lower und upper auf und mache dann den Vergleich.

Code:
Test t3 = new Test(7,5);
System.out.println(t3.isEmpty);

Ich kriege hier aber trotzdem immer false.
 

Tobias

Top Contributor
Jo, weil du im aufgerufenen Konstruktor isEmpty nicht initialisierst. Die Reihenfolge im Constructor-Chaining geht vom Konstruktor mit wenigen Parametern hin zum Konstruktor mit vielen Parametern, wobei für die "überschüssigen" Parameter Standard- oder berechnete Werte eingesetzt werden. EDIT: Dein Chaining ist genau verkehrt herum.
 

rumpi

Mitglied
Code:
public Test(int lower, int upper){
		this.lower = lower;
		this.upper = upper;
		if (lower>=upper)
			isEmpty=true;
		else 
			isEmpty=false;
	}
Wenn ich es in dem Konstruktor initialisiere, dann brauch ich doch

Code:
public Test(int lower, int upper, boolean isEmpty){
		
	}

nicht mehr!?
Natürlich funktioniert es dann :/
 

Tobias

Top Contributor
Ja, wie schon gesagt, ist dieser dritte Konstruktor Blödsinn, weil isEmpty von upper und lower abhängt. Du hast in aber nunmal an der Backe, also wirst du ihn implementieren müssen. Die einzig sinnvolle Implementierung (es sei denn, man macht in private und degradiert ihn so zum reinen Attribute-Setzer, weil er den Argumenten dann bedingungslos vertrauen dürfte) ist, isEmpty selbst zu berechnen und dieses Wert mit dem übergebenen abzugleichen. Wenn die beiden übereinstimmen ist alles super, ansonsten hat der Aufrufer einen Fehler gemacht, der mit einer Exception zu beantworten wäre.

EDIT: Mach es erstmal bis hierhin (also bis zum Exception-Werfen in Konstruktor 3) fertig, dann können wir uns anschauen, wie man sich mit Constructor-Chaining Schreibarbeit spart.
 

rumpi

Mitglied
Meinst du so:

Code:
public Test(int lower, int upper){
		this.lower = lower;
		this.upper = upper;
		if (lower>=upper)
			isEmpty=true;
	}
	public Test(int lower, int upper, boolean isEmpty){
		if(lower>=upper)
			isEmpty=true;
		if (this.isEmpty!=isEmpty)
			throw  new  IndexOutOfBoundsException("nicht so gut");
	}

Das ist die einzige Exeption, die wir bisher hatten.

Edit: Ich verstehe dann aber echt nicht, wie man als erste Aufgabe so einen Unsinn machen lassen kann.

Das kommt ja wirklich nur zum Widerspruch, wenn ich sowas mache...

Code:
Test t2 = new Test(7,10,true);
 

Tobias

Top Contributor
Naja, IndexOutOfBoundsException ist hier zwar nicht passend, aber genau so war's gemeint. Ich würde eher IllegalArgumentException oder IllegalStateException werfen, wobei IllegalArgument besser passt.

Damit das ganze etwas mehr Sinn macht, solltest du den 3. Konstruktor in der Sichtbarkeit einschränken - am besten private. Dadurch kann ein externer Client (irgendeine andere Klasse) diesen Konstruktor nicht mehr aufrufen (mit der Alternative protected unter bestimmten Voraussetzung schon, aber da ist das dann meist gewollt, siehe Vererbung etc - behandelt ihr wahrscheinlich später). Auf deine main()-Methode haben diese Beschränkungen allerdings keine Auswirkungen, denn die befindet sich ja in derselben Klasse.

Anschließend rufst du den 3. Konstruktor von den beiden anderen Konstruktoren aus auf, wobei du für isEmpty jeweils einen sinnvollen Wert übergibst - weil der 3. Konstruktor jetzt private ist, und somit nur durch Code aufgerufen wird, der sich in derselben Klasse befindet und sich deshalb an die geltenden Regeln hält (halten sollte, wenn nicht, liegt ein Programmierfehler vor), kann auf die Exception und die Überprüfung wieder verzichtet werden. Im 3. Konstruktor werden dann nur noch die Attribute gesetzt.

Falls du diese Aufgabe abgeben mußt, solltest du diese letzten Schritte gut kommentieren (folge einfach der Argumentationslinie meiner Erklärungen), weil das eine "intelligente" Lösung ist, die dein Prof eventuell für ein Umgehungsmanöver hält, weil er glaubt, du habest Exceptions nicht verstanden oder nicht gesehen, dass hier ein illegaler Wert von außen übergeben werden könnte.
 

rumpi

Mitglied
So?
Code:
	public Test(){
		this.isEmpty=isEmpty;
		isEmpty=true;
	}
	public Test(int lower){
		this.lower = lower;
		this.upper = lower;
		this.isEmpty=isEmpty;
		isEmpty=false;
		
	}
	public Test(int lower, int upper){
		this.lower = lower;
		this.upper = upper;
		this.isEmpty=isEmpty;
		if (lower>=upper)
			isEmpty=true;
	}
	private Test(int lower, int upper, boolean isEmpty){
		/**if(lower>=upper)
			isEmpty=true;
		if (this.isEmpty!=isEmpty)
			throw  new  IllegalArgumentException("nicht so gut");*/
	}
 

Tobias

Top Contributor
Nein, so:

Code:
public Test() {
    this(0, 0); // Aufruf von Konstruktor 2
}

public Test(int lower, int upper) {
    this(lower, upper, lower >= upper); // Aufruf von Konstruktor 3
}

// Private, damit nur vertrauenswürdiger (nämlich deiner) Code drankommt
private Test(int lower, int upper, boolean isEmpty) {
    this.lower = lower;
    this.upper = upper;
    this.isEmpty = isEmpty;
}
 

rumpi

Mitglied
Jetzt bin ich erstmal baff, dass man das so darf.
Sag mal, wozu eigentlich die get und set Methoden? Nur zum Spass? Für die Berechnung, der Länge, von contains, diskunkt, dem schnitt und der hülle, sind die doch unwichtig.
 

Tobias

Top Contributor
Die set- und get-Methoden hab ich hier der Einfachheit wegen ignoriert. Grundsätzlich sollte man zum Zugriff auf Attribute immer die Setter und Getter benutzen, weil man dann einen zentralen Punkt hat, an dem Typprüfungen und eventuelle Umrechnungen stattfinden können (Letzteres etwa wenn sich die Klasse intern ändert, nach außen hin aber kompatibel bleiben muss). Wobei ich bei Wertklassen wie deinem Intervall grundsätzlich dazu tendiere, das Ganze immutable, also unveränderlich, zu halten, wegen der damit verbundenen Vorteile Einfachheit und inhärenter Threadsicherheit. Aber das ist ein ganz anderes Thema.
 

rumpi

Mitglied
Ok, hab jetzt alles mit get/set Methoden.
Mal ne Frage zur Hülle.
Ist die Hülle von (5,10) und (2,3) = (2,10) ?
Und was ist die Hülle, wenn die Leere Menge im Spiel ist (z.b. () und (3,12))?
 

Tobias

Top Contributor
Ein leeres Intervall [] läßt sich mit dieser Klasse ja gar nicht konstruieren, weil immer eine obere und untere Grenze vorhanden ist (im Zweifelsfall eben 0). Die Hülle hast du schon ganz richtig beschrieben.

Zu Gettern und Settern: Hast du sichergestellt, das isEmpty bei einem nachträglichen Aufruf von setUpper() oder setLower() immer den richtigen Wert enthält? Teste mal folgendes gegen deinen aktuellen Code:

Code:
Test t = new Test(1, 10);
System.out.println(t.isEmpty()); // false
t.setUpper(1);
System.out.println(t.isEmpty()); // true
t.setUpper(10);
System.out.println(t.isEmpty()); // false
t.setLower(10);
System.out.println(t.isEmpty()); // true
t.setLower(1);
System.out.println(t.isEmpty()); // false

EDIT. Das ist übrigens der Grund, warum unveränderliche Objekte soviel einfacher zu handhaben sind.
 

rumpi

Mitglied
Müsste Zeile 4 nicht false liefern?
(1,1) Hat doch 1 als Element und ist nicht leer.
Genauso ist doch (10,10) nicht leer!?
Dem zu Folge käme überall false.
Oder steh ich grad auf der Leitung?
 

Tobias

Top Contributor
Ein Intervall bei dem obere und untere Grenze gleich sind, ist leer. Ansonsten könnte deine Klasse keine leeren Intervalle abbilden.
 

rumpi

Mitglied
Danke für den Hinweis. Der war ja sogar Aufgabenrelevant. Habe eine if-Abfrage in die set-Methoden eingebaut, die isEmpty gegebenenfalls auf true setzen.

Wenn du magst, wirf doch noch mal nen abschließenden Blick auf den Code. Vlt würdest du manche Sachen schlauer umsetzen.

Code:
public class Test {
	
	private int lower, upper;
	private boolean isEmpty;
	
	public Test(){
		this (0,0);
		isEmpty=true;
	}
	public Test(int lower){
		this.setLower(lower);
		this.setUpper(lower);
		isEmpty=true;
	}
	public Test(int lower, int upper){
		this(lower, upper, lower>=upper);
	}	
	private Test(int lower, int upper, boolean isEmpty){
		this.setLower(lower);
	    this.setUpper(upper);
	    this.isEmpty = isEmpty;
	}
	public int getLower(){
		return this.lower;
	}
	public int getUpper(){
		return this.upper;
	}
	public void setLower(int lower){
		this.lower = lower;
		if (this.lower>=this.upper)
			isEmpty=true;
		else
			isEmpty=false;
	}
	public void setUpper(int upper){
		this.upper = upper;
		if (this.upper<=this.lower)
			isEmpty=true;
		else
			isEmpty=false;
	}
	public String toString(){
		return "[" + getLower() + ".." + getUpper() + "]";
	}
	public int length(){
		if (isEmpty==true)
			return 0;
		else
			return getUpper()-getLower()+1;
	}
	public boolean contains(int t){
		if (t>=getLower() & t<=getUpper())
				return true;
		else
			return false;
	}
	public boolean contains(Test t){
		if (t.getLower()>=getLower() && t.getUpper()<=getUpper())
			return true;
		else
			return false;		
	}
	public boolean disjoint(Test t){
		if (t.getLower()>getUpper() | t.getUpper()<getLower())
			return true;
		else
			return false;
	}
	public Test schnitt(Test t){
		if (this.contains(t.getLower())==true & this.contains(t.getUpper())==true)
			return t;
		else if (t.getLower()<=this.getLower() & t.getUpper()>=this.getLower())
			return this;
		else if (this.contains(t.lower)==false & this.contains(t.upper)==true){
			t.setLower(this.getLower());
			return t;			
		}
		else if (this.contains(t.getLower())==true & this.contains(t.getUpper())==false){
			t.setUpper(this.getUpper());
			return t;
		}
		else
			System.out.println("Intervalle sind disjunkt");
			return new Test();
	}
	public Test huelle(Test t){
		if(this.getLower()<t.getLower() & this.getUpper()>t.getUpper())
			return this;
		else if (this.getLower()>t.getLower() & this.getUpper()<t.getUpper())
			return t;			
		else if (this.getLower()<t.getLower() & this.getUpper()<t.getUpper()){
			t.setLower(this.getLower());
			return t;
		}	
		else if(this.getLower()>t.getLower() & this.getUpper()>t.getUpper()){
			t.setUpper(this.getUpper());
			return t;
		}
		else 
			return new Test();
	}

}
 

Landei

Top Contributor
Sowas:
Code:
public boolean contains(int t){
      if (t>=getLower() & t<=getUpper())
            return true;
      else
         return false;
   }
...schreibt man so:
Code:
public boolean contains(int t){
    return (t>=getLower() & t<=getUpper());
}
 

Landei

Top Contributor
Und sowas:
Code:
if (this.contains(t.getLower())==true & this.contains(t.getUpper())==true) {...}
...schreibt man so:
Code:
if (this.contains(t.getLower()) && this.contains(t.getUpper())){...}
 

rumpi

Mitglied
Macht die Sache natürlich schlanker, danke für den Hinweis!
&& heißt, dass beide Seiten erfüllt sein müssen, oder?
 

Landei

Top Contributor
Im Übrigen würde ich die Klasse unveränderlich (immutable) machen, falls es die Aufgabenstellung erlaubt, also keine setter-Methoden.
In den Methoden schnitt und huelle veränderst du den übergebenen Parameter t, d.h. er ist auch im aufrufenden Kontext verändert. Das ist extrem fehlerträchtig. Wenn du schon ein Objekt veränderst, dann höchstens this, aber wie gesagt würde ich empfehlen, die Klasse unveränderlich zu machen, und ein neues Objekt zu kreieren, wenn die vorhandenen nicht passen. Objekterzeugungen sind für solche Mini-Klassen wirklich billig, und Performance-Tuning solltest du wirklich sein lassen, wenn es nicht erforderlich ist.
 

rumpi

Mitglied
Setter und Getter Methoden sind in der Aufgabe Pflicht.
Daher dachte ich, ich wende sie dort an, wo man sie anwenden kann.
 

Landei

Top Contributor
& ist eine bit-operation, also wenn du 7 & 10 schreibst, wäre das binär 0111 & 1010, und dann werden die einzelnen Stellen "geunded", was 0010 = 2 ergibt.
&& ist der boolescher Operator "und", der nicht auf Zahlen angewandt werden kann.
Beide Operatoren liefern für booleans die gleichen Werte, allerdings ist && cleverer, weil er short-circuit-logic ("Kurzschlusslogik") benutzt, während & immer beide Operanden auswertet.

Code:
boolean f(boolen value) {
   System.out.println("" + value);
   value;
}

boolean x = f(false) & f(true); //druckt "false" und "true"
boolean y = f(false) && f(true); //druckt nur "false"
 

Landei

Top Contributor
Setter und Getter Methoden sind in der Aufgabe Pflicht.
Deine Lehrer sollte man zu Cobol nicht unter 10 Jahren verurteilen. Unveränderliche Klassen sind konzeptionell einfacher, haben entsprechend weniger Bugs und sind sicherer zu handhaben.

Bei Sun haben sie die Lektion inzwischen einigermaßen gelernt, aber wir haben immer noch unter solchen Krankheiten wie java.util.Date zu leiden...
 

rumpi

Mitglied
Ui, jetzt wirste aber ganz schön fachspezifisch. Ich zweifle ja nicht an, was du sagst... zumal das dein Vorredner auch schon angedeutet hat. Ich denke, der Prof wollte das einfach mal "geübt" haben. So einfach. Glaube er würde deine Meinung im Allgemeinen aber teilen.
 

Tobias

Top Contributor
Hier noch ein paar Kommentare von mir:

Code:
public class Test {
   
   private int lower, upper;
   private boolean isEmpty;
   
   public Test(){
      this (0,0);
      isEmpty=true; // Unnötig, Konstruktor 2 kümmert sich darum
   }
   public Test(int lower){
      this.setLower(lower); //Ersetzen durch: this(lower, lower);
      this.setUpper(lower);
      isEmpty=true;
   }
   public Test(int lower, int upper){
      this(lower, upper, lower>=upper);
   }   
   private Test(int lower, int upper, boolean isEmpty){
      this.setLower(lower);
       this.setUpper(upper);
       this.isEmpty = isEmpty;
   }
   public int getLower(){
      return this.lower;
   }
   public int getUpper(){
      return this.upper;
   }
   public void setLower(int lower){
      this.lower = lower;
      // Diesen Code-Schnipsel könnte man auslagern in eine 
      // private Methode checkIfEmpty(). Spart Schreibarbeit.
      if (this.lower>=this.upper)
         isEmpty=true;
      else
         isEmpty=false;
   }
   public void setUpper(int upper){
      this.upper = upper;
      if (this.upper<=this.lower)
         isEmpty=true;
      else
         isEmpty=false;
   }
   public String toString(){
      return "[" + getLower() + ".." + getUpper() + "]";
   }
   public int length(){
      if (isEmpty==true)
         return 0;
      else
         // Halte ich für nicht korrekt, die Grenzen des Intervalls
         // interpretiere ich als exklusiv. Dann müßte es hier -1
         // heißen - andernfalls wäre Intervall [0,0] nicht leer.
         return getUpper()-getLower()+1;
   }
   public boolean contains(int t){
      // siehe Landei-> logische Operatoren nutzen!
      // siehe Landei-> boolean-Wert direkt zurückgeben
      if (t>=getLower() & t<=getUpper())
            return true;
      else
         return false;
   }
   public boolean contains(Test t){
      // siehe Landei-> boolean-Wert direkt zurückgeben
      if (t.getLower()>=getLower() && t.getUpper()<=getUpper())
         return true;
      else
         return false;      
   }
   public boolean disjoint(Test t){
      // siehe Landei-> logische Operatoren nutzen! (||)
      // siehe Landei-> boolean-Wert direkt zurückgeben
      if (t.getLower()>getUpper() | t.getUpper()<getLower())
         return true;
      else
         return false;
   }
   //siehe Landei-> nicht t oder this verändern, sondern neues
   // Intervall mit den richtigen Grenzen anlegen und dieses zurückgeben
   public Test schnitt(Test t){
      if (this.contains(t.getLower())==true & this.contains(t.getUpper())==true)
         return t;
      else if (t.getLower()<=this.getLower() & t.getUpper()>=this.getLower())
         return this;
      else if (this.contains(t.lower)==false & this.contains(t.upper)==true){
         t.setLower(this.getLower());
         return t;         
      }
      else if (this.contains(t.getLower())==true & this.contains(t.getUpper())==false){
         t.setUpper(this.getUpper());
         return t;
      }
      else
         System.out.println("Intervalle sind disjunkt");
         return new Test();
   }
   // siehe Landei-> neues Intervall mit den richtigen Grenzen anlegen
   // und dieses zurückgeben.
   public Test huelle(Test t){
      if(this.getLower()<t.getLower() & this.getUpper()>t.getUpper())
         return this;
      else if (this.getLower()>t.getLower() & this.getUpper()<t.getUpper())
         return t;         
      else if (this.getLower()<t.getLower() & this.getUpper()<t.getUpper()){
         t.setLower(this.getLower());
         return t;
      }   
      else if(this.getLower()>t.getLower() & this.getUpper()>t.getUpper()){
         t.setUpper(this.getUpper());
         return t;
      }
      else
         return new Test();
   }

}
 

rumpi

Mitglied
Danke, dass du dir so viel Mühe gegeben hast. Ich habe versucht, deine Vorschläge umzusetzen.

public int length(){
if (isEmpty==true)
return 0;
else
// Halte ich für nicht korrekt, die Grenzen des Intervalls
// interpretiere ich als exklusiv. Dann müßte es hier -1
// heißen - andernfalls wäre Intervall [0,0] nicht leer.
return getUpper()-getLower()+1;
}

Das Intervall [0,0] käme auch gar nicht in else rein, da es ja leer ist (isEmpty==true).

Ich habe nun überall noch den Fall isEmpty betrachtet. Das macht die Geschichte furchtbar groß. Unser Prof sprach davon, dass jede Methode nur 2-3 Zeiler wären (ok, vlt waren es auch 3-4 Zeiler), aber es sieht jetzt schon gewaltig aus.
Jedoch passen jetzt alle Beispiele aus dem Testfragment der Aufgabe.

Code:
public class Test {
	
	private int lower, upper;
	private boolean isEmpty;
	
	public Test(){
		this (0,0);
	}
	public Test(int lower){
		this(lower,lower);
	}
	public Test(int lower, int upper){
		this(lower, upper, lower>=upper);
	}	
	private Test(int lower, int upper, boolean isEmpty){
		this.setLower(lower);
	    this.setUpper(upper);
	    this.isEmpty = isEmpty;
	}
	public int getLower(){
		return this.lower;
	}
	public int getUpper(){
		return this.upper;
	}
	public void setLower(int lower){
		this.lower = lower;
		if (this.lower>=this.upper)
			isEmpty=true;
		else
			isEmpty=false;
	}
	public void setUpper(int upper){
		this.upper = upper;
		if (this.upper<=this.lower)
			isEmpty=true;
		else
			isEmpty=false;
	}
	public String toString(){
		return "[" + getLower() + ".." + getUpper() + "]";
	}
	public int length(){
		if (isEmpty==true)
			return 0;
		else
			return getUpper()-getLower()+1;
	}
	public boolean contains(int t){
		if (this.isEmpty==true)
			return false;
		else
			return (t>=getLower() && t<=getUpper());
	}
	public boolean contains(Test t){
		if (this.isEmpty==true && t.isEmpty==false)
			return false;
		else 
			return (t.getLower()>=getLower() && t.getUpper()<=getUpper());
	}
	public boolean disjoint(Test t){
		if (this.isEmpty==true || t.isEmpty==true)
			return true;
		else
			return (t.getLower()>getUpper() || t.getUpper()<getLower());
	}
	public Test schnitt(Test t){
		if (this.isEmpty==true || t.isEmpty==true)
			return new Test();
		else {
			if (this.contains(t.getLower()) & this.contains(t.getUpper()))
				return t;
			else if (t.getLower()<=this.getLower() & t.getUpper()>=this.getLower())
				return this;
			else if (this.contains(t.lower)==false & this.contains(t.upper)==true){
				Test schnitt = new Test();
				schnitt.setLower(this.getLower());
				schnitt.setUpper(t.getUpper());
				return schnitt;			
			}
			else if (this.contains(t.getLower())==true & this.contains(t.getUpper())==false){
				t.setUpper(this.getUpper());
				return t;
			}
			else {
				System.out.println("Intervalle sind disjunkt");
				Test schnitt = new Test(0);
				return schnitt;
			}
		}
	}
	public Test huelle(Test t){
		if (this.isEmpty==true)
			return t;
		else if (t.isEmpty==true)
			return this;
		else {
			if(this.getLower()<t.getLower() & this.getUpper()>t.getUpper())
				return this;
			else if (this.getLower()>t.getLower() & this.getUpper()<t.getUpper())
				return t;			
			else if (this.getLower()<t.getLower() & this.getUpper()<t.getUpper()){
				Test huelle = new Test();
				huelle.setLower(this.getLower());
				huelle.setUpper(t.getUpper());
				return t;
			}	
			else if(this.getLower()>t.getLower() & this.getUpper()>t.getUpper()){
				Test huelle = new Test();
				huelle.setUpper(this.getUpper());
				huelle.setLower(t.getLower());
				return t;
			}
			else 
				return new Test();
		}
	}
	public static void main (String[] args){
		Test t1 = new Test();
		Test t2 = new Test(7,10);
		Test t3 = new Test(7,5);
		Test t4 = new Test(7,9);
		Test t5 = new Test(8,10);
		Test t6 = new Test(7);
		System.out.println(t1 + "   Länge: " + t1.length());
		System.out.println(t1.contains(8));
		System.out.println(t2.contains(t3));
		System.out.println(t3.contains(t4));
		System.out.println(t1.contains(t5));
		System.out.println(t1.huelle(t5));
		System.out.println(t5.huelle(t1));
		System.out.println(t4.schnitt(t5));
		System.out.println(t4.disjoint(t5));
		System.out.println(t6.disjoint(t5));
		
	}

}
 

Tobias

Top Contributor
Soweit sieht das gut aus. Ab und zu kannst du das Setzen von isEmpty noch zusätzlich verkürzen, in dem du statt eine if-Abfrage zu benutzen, den boolean-Wert direkt setzt:

statt:
Code:
if(this.getLower() >= this.getUpper()) {
    isEmpty = true;
} else {
    isEmpty = false;
}

einfacher:
Code:
isEmpty = this.getLower() >= this.getUpper();

Aber das sind Kleinigkeiten.

Was ich dagegen an length() auszusetzen haben, ist schon größerer Natur: Mit deiner Implementierung des Intervalls würde [7, 10] eine Länge 4 ergeben: 10-7+1=4, das heißt beide Grenzen sind Teil des Intervalls! Das bedeutet, das ich für Intervall [0,0] eine Länge von 1 erwarten kann: 0-0+1=1; es kommt aber 0 heraus (weil isEmpty true ist)! Das ist inkonsistent.

Das modellierte Intervall ist halboffen, die Längenberechnung muß also der Regel upper-lower folgen (aber nicht upper-lower-1, wie ich gestern abend noch behauptet habe - dann wäre unsere Interpretation eines leeren Intervalls noch nicht vollständig, denn Intervalle wie [0, 1] wären dann ebenfalls leer, das Intervall also offen). Dann könnte man die Abfrage von isEmpty wiederum weglassen und durch diesen Ausdruck ersetzen:

Code:
public int length() {
    return Math.max(0, getUpper()-getLower());
}

Math.max() liefert das Maximum der übergebenen Werte zurück. Ist das Intervall leer, so wird die Länge bei der gegebenen Berechnungsformel entweder 0 oder negativ. Ist es dagegen nicht leer, so bleibt der rechte Ausdruck positiv.
 
M

Muchiste

Gast
aber ein intervall mit lower=upper (zb. [0..0]) beinhaltet die 0 und hat daher die länge 1 und isempty == false;
das intervall [0,4] hat doch auch die länge 5, weil es ein geschlossenes intervall ist und daher die intervallsgrenzen mit inbegriffen sind.
ein leeres intervall wäre zb [5,1]. da wäre isempty == true.
zudem existiert meiner meinung nach keine hülle, wenn 2 intervalle disjunkt sind.
und kein schnittpunkt wenn die intervalle disjunkt bzw leer sind.

oder irre ich mich da?
 

rumpi

Mitglied
Das dachte ich zuerst auch. Aber die Aufgabe gibt nicht genau her, ob es halboffene, offene oder geschlossene Intervalle sind.
Rein von der mathematischen Konvention bedeuten Klammern ja offene Intervalle.
Was die Hülle betrifft, da müsstest du dich irren. Im Beispiel der Aufgabe heißt es, dass die Hülle von [3..6] & [8..12] - [3..12] sei.
Aber ohne dieses Beispiel hätte ich nicht gewusst, was zu tun ist.
Ich kenne nur die lineare Hülle, kann sie aber nicht recht anweden :/
 
M

muchiste

Gast
das sind geschlossene intervalle.
1. [a,b] ist mathematisch ein geschlossenes intervall ( ]a,b[ wäre zb offen)
2. steht ganz oben im aufgabenkopf: x>= a und x<= b; dh. dass die intervallsgrenzen im intervall liegen, somit auch zb[0..0] kein leeres intervall ist und auch die länge 1 hat.

bei der hülle geb ich dir recht.

deswegen frage ich mich wie man ein leeres intervall darstellen soll, wenn man zb den schnitt zweier disjunkter intervalle ermitteln soll, was ja die leere menge ist
 

rumpi

Mitglied
Du weißt aber, dass runde Klammern auch für offene Intervalle stehen?
Aber ich verstehe, was du meinst. Ich werde von geschlossenen Intervallen ausgehen. Das macht die Geschichte einfacher. x>= a und x<= b werden dann natürlich x>a und x<b. Somit hat [0..0] wieder die Länge eins.
Was den Schnitt disjunkter Intervalle angeht, so werde ich [0..0] und ne println ausgeben (sowas wie Intervalle sind disjunkt, es gibt keinen Schnitt bzw leere Menge.
 

Landei

Top Contributor
Du könntest das leere Intervall als speziellen, unveränderlichen Wert (wie etwa nil in einer verketteten Liste) angeben:

Code:
public class Test { 
   public static final Test EMPTY = new Test() {
      public int getLower() {
         throw UnsupportedOperationException();
      }
      public void setLower(int lower) {
         throw UnsupportedOperationException();
      }
      public int getUpper() {
         throw UnsupportedOperationException();
      }
      public void setUpper(int upper) {
         throw UnsupportedOperationException();
      }
      public boolean contains(Test t){ 
          return false; 
      }
      public boolean isEmpty() {
          return true; 
      }
      //usw.
   }

   public boolean isEmpty() {
       return false; 
   }

   //use.
}

Wahrscheinlich wäre diese Lösung "noch sauberer", da müßtest du aber einiges ändern:
Code:
interface Intervall {
   boolean isEmpty();
   boolean contains(Intervall v);
   ... 
}

//singleton
class Empty implements Intervall {
   public static final Intervall instance = new Empty();
   private Empty(){} 
   boolean isEmpty(){return true;}
   boolean contains(Intervall v){ return false; }
   ...
}

class Test implements Intervall {
   private int lower, higher;
   public Test(int lower, int higher) {
      this.lower = lower;
      this.higher = higher;
   }

   boolean isEmpty(){return false;}
   boolean contains(Intervall v){ 
       if(v == Empty.instance) {
           ...
       } else {
          Test t = (Test) v;
          ... 
       }
   }
   public int getLower() {
     return lower;
   }
   ...
}
 
G

Gast

Gast
Kurze Frage:
public String toString(){
return "[" + getLower() + ".." + getUpper() + "]";
}
kann man doch auch so schreiben oder ? :

public String toString(){
return "[" + this.lower + ".." + this.upper + "]";
}

oder hat das in irgendwelchen fällen andere auswirkungen, hab bisher keine festgestellt.
 
G

Guest

Gast
rumpi hat gesagt.:
Code:
public class Test {
	
	private int lower, upper;
	private boolean isEmpty;
	
	public Test(){
		//this (0,0);
                  this.lower = 0;
                  this.upper = 0;
	}
	public Test(int lower){
		//this(lower,lower);
                this.lower = lower;
                this.upper = lower;
	}
	public Test(int lower, int upper){
		this(lower, upper, lower>=upper);
	}	
	private Test(int lower, int upper, boolean isEmpty){
		this.setLower(lower);
	    this.setUpper(upper);
	    this.isEmpty = isEmpty;
	}
...
	public static void main (String[] args){
		Test t1 = new Test();
		Test t6 = new Test(7);
		System.out.println(t1 + "   Länge: " + t1.length());
		System.out.println(t6 + "   Länge: " + t6.length());
		
	}

}

mal ne frage zum verständnis. habe zeile 7 und zeile 12 geändert. zu dem was jeweil darunter steht. sollte dies nicht wenn man dann den ganzen code betrachtet das gleiche ergeben ? jedoch ändert sich durch die änderung die länge des intervalls von 0 zu 1.
 
G

Gast

Gast
ok. isEmpty ist deshalb nicht true weil diese änderung quasi Test t1 = new Test(0,0) entspräche oder ? und dadurch kein leeres intervall entsteht ?
dann noch eine kleinigkeit.
this(lower, upper, lower>=upper);
bedeutet: this.lower = lower; this.upper = upper
wenn lower nicht >= upper ist ?
 

coree

Mitglied
so hab mich nun auch mal hier angemeldet. durch einiges rumprobieren hat sich meine frage nun selbst beantwortet.
da für mich ein leeres intervall die länge 0 hat und das intervall [1..1] die länge 1 hab ich den code etwas verändert und hoffe auch auf die richtige weise und nicht zufällig mir was richtiges zusammen geschustert zu haben:
public Test(){
this (0,0, true);
}
public Test(int lower){
this(lower,lower);
}
public Test(int lower, int upper){
this(lower, upper, lower>upper);
}
 

Tobias

Top Contributor
Siehe obige Diskussion darüber, ob das abgebildete Intervall offen, halboffen oder geschlossen ist und welche Implikationen das für length() und isEmpty hat ...
 

coree

Mitglied
jo das habe ich gesehen, wollte nur wissen ob das was ich geschrieben habe für meine definition richtig ist
aber sollte passen.
 

Tobias

Top Contributor
Der leere Konstruktor sollte ein leeres Intervall schaffen. [0..0] ist aber nicht leer nach deiner Definition -> Die isEmpty-Initialisierung ist also über die beiden Konstruktoren nicht konsistent, denn Intervall(0,0) ergäbe ein NICHT-LEERES Intervall mit den Grenzen 0 und 0.
 
Status
Nicht offen für weitere Antworten.
Ähnliche Java Themen
  Titel Forum Antworten Datum
M isEmpty() Java Basics - Anfänger-Themen 11
G isEmpty und if-anweisung Java Basics - Anfänger-Themen 4
M Rest mit Spring boot oder selbst anlegen Java Basics - Anfänger-Themen 14
B Hotkeys selbst definieren? Java Basics - Anfänger-Themen 1
berserkerdq2 An selbst ersteller txt Datei immer Text dranhängen, ohne den vorherign Text zu löschen Java Basics - Anfänger-Themen 8
J selbst erstellte Datei mit Programm öffnen Java Basics - Anfänger-Themen 10
J ArrayList add methode selbst programmieren Java Basics - Anfänger-Themen 10
CptK Generics: Klassen die Interface implementieren, aber selbst nicht das Interface sind Java Basics - Anfänger-Themen 8
ruutaiokwu Bluetooth-Zugriff, braucht es dazu plattformabhängige Libraries oder kann das Java mittlerweile selbst? Java Basics - Anfänger-Themen 10
I Klasse selbst fortlaufend nummerieren lassen Java Basics - Anfänger-Themen 11
U Hashmap Iterator selbst implementieren Java Basics - Anfänger-Themen 10
S Tokenizer selbst implementieren Java Basics - Anfänger-Themen 1
M WindowStateListener selbst implementieren Java Basics - Anfänger-Themen 8
G MapStruct Anwendung vom selbst geschriebenen Formater Java Basics - Anfänger-Themen 4
F Kindklassen sollen Ihre Methoden selbst implementieren Java Basics - Anfänger-Themen 5
G Objekt der selben Klasse wie selbst mit Aufrufen des Konstruktors erzeugen Java Basics - Anfänger-Themen 14
S Code richtig / besser machbar? (Nicht sicher, ob Code selbst falsch ist) Java Basics - Anfänger-Themen 4
B Wie kann ich eine Methode einer selbst erstellten Klasse statisch importieren? Java Basics - Anfänger-Themen 5
I TreePath selbst erstellen und expandPath Java Basics - Anfänger-Themen 6
O Werte selbst eintragen Java Basics - Anfänger-Themen 9
T Selbst erstellten Dateityp mit java Programm assoziieren? Java Basics - Anfänger-Themen 4
K Selbst renderndes Object auf null setzen Java Basics - Anfänger-Themen 1
M Eclipse startet nicht mehr (eclipse.exe beendet sich selbst)? Java Basics - Anfänger-Themen 5
D Exception selbst Implementieren Java Basics - Anfänger-Themen 1
E Array von Objekten einer selbst definierten Klasse mit eindeutigem Namen Java Basics - Anfänger-Themen 2
M Java Datei soll sich selbst löschen Java Basics - Anfänger-Themen 8
M Java Bukkit Plugin (selbst erstellt) Java Basics - Anfänger-Themen 9
S Listen Klasse selbst schreiben Java Basics - Anfänger-Themen 6
B Methoden Methode lässt sich nicht selbst aufrufen? Java Basics - Anfänger-Themen 3
H JFileChooser... dateispeicherpfad selbst aussuchen Java Basics - Anfänger-Themen 4
L Klassen Kann eine Klasse sich selbst returnen? Java Basics - Anfänger-Themen 26
T methode ruft sich selbst auf Java Basics - Anfänger-Themen 28
J importieren von selbst definierten klassen Java Basics - Anfänger-Themen 10
M JButton selbst nachprogrammieren Java Basics - Anfänger-Themen 3
J selbst erstellte Hashtabelle -- Warum Exception? Java Basics - Anfänger-Themen 3
K indexOf selbst rekursiv definieren Java Basics - Anfänger-Themen 4
M selbst gezipptes File lässt sich nicht öffnen Java Basics - Anfänger-Themen 2
S Deserialisieren auf sich selbst Java Basics - Anfänger-Themen 4
Developer_X JButton removt sich selbst Java Basics - Anfänger-Themen 32
R Ein/Ausleseproblem von Datei mit selbst erstellten Objekten Java Basics - Anfänger-Themen 10
M "Selbst erstellte" Buttons nicht sichtbar. Java Basics - Anfänger-Themen 20
D Bei Event soll Instanz sich selbst löschen Java Basics - Anfänger-Themen 4
K Wieso schaltet meine CheckBox von selbst um ? Java Basics - Anfänger-Themen 31
F JOptionPane selbst programmieren Java Basics - Anfänger-Themen 8
E Eine Klasse hat eine Instanz von sich selbst. Java Basics - Anfänger-Themen 6
L vor- und zurückblättern selbst gemacht Java Basics - Anfänger-Themen 18
G Button selbst entwerfen Java Basics - Anfänger-Themen 9
G Mit "instanceof" sich selbst Fragen? Java Basics - Anfänger-Themen 4
G Array von selbst-definiertem Typ Java Basics - Anfänger-Themen 3
R Comparable Interface Funktionalität selbst programmieren? Java Basics - Anfänger-Themen 3
B Programm sich selbst neu starten lassen Java Basics - Anfänger-Themen 8
D Thread soll sich selbst beenden Java Basics - Anfänger-Themen 8
G Objektarray mit sich selbst rekombinieren Java Basics - Anfänger-Themen 5
B Objekt soll sich selbst löschen Java Basics - Anfänger-Themen 25
K Vector mit sich selbst vergleichen Java Basics - Anfänger-Themen 2
rambozola selbst definierte exception abfangen funzt nicht Java Basics - Anfänger-Themen 14
M Spielerbewegungen realisieren Java Basics - Anfänger-Themen 2
A MouseMotionListener - wie Mausverfolgung und Neuzeichnen realisieren? Java Basics - Anfänger-Themen 12
H Frage um Eingbeaufforderung zu realisieren Java Basics - Anfänger-Themen 4
A Wie kann ich folgendes Projekt realisieren? Java Basics - Anfänger-Themen 4
L Methoden Methode mit drei Rückgabewerten realisieren Java Basics - Anfänger-Themen 3
L Schaltung realisieren Java Basics - Anfänger-Themen 3
J Frage Antwort Spiel - Wie Zeitcountdown realisieren? Java Basics - Anfänger-Themen 2
L Liste als Array realisieren Java Basics - Anfänger-Themen 23
J Mustererkennung realisieren Java Basics - Anfänger-Themen 10
Y chat programm im internet realisieren Java Basics - Anfänger-Themen 5
Z Wie repaint() bei Uhr realisieren? Java Basics - Anfänger-Themen 12
T Kleines Spiel realisieren - wie? Java Basics - Anfänger-Themen 6
T 1:1 Beziehungen realisieren ? Java Basics - Anfänger-Themen 13
S Ausgabe realisieren Java Basics - Anfänger-Themen 2
S Grössere MenuBars realisieren Java Basics - Anfänger-Themen 7
D Java Programm mit Internetzugriff realisieren Java Basics - Anfänger-Themen 8
ARadauer timeout realisieren Java Basics - Anfänger-Themen 5
D Logging sätmlicher Vorgänge, wie am besten realisieren? Java Basics - Anfänger-Themen 6
G Physikalisches Problem realisieren Java Basics - Anfänger-Themen 11
U Texteditor mit methoden realisieren Java Basics - Anfänger-Themen 13
A Beziehung 1-n in Java realisieren Java Basics - Anfänger-Themen 17
S Zeilenumbrüche realisieren Java Basics - Anfänger-Themen 6
I SaveFile Dialog - wie realisieren ? Java Basics - Anfänger-Themen 4
L Timer Swing realisieren Java Basics - Anfänger-Themen 4
P :shock: teilweises wurzelziehen realisieren Java Basics - Anfänger-Themen 9
R Zeitaufwand für Suchmaschine mit Lucene realisieren Java Basics - Anfänger-Themen 3

Ähnliche Java Themen

Neue Themen


Oben