Informatiker Board (http://www.informatikerboard.de/board/index.php)
- Sonstiges (http://www.informatikerboard.de/board/board.php?boardid=2)
-- Off-Topic (http://www.informatikerboard.de/board/board.php?boardid=3)
--- Java Applet (http://www.informatikerboard.de/board/thread.php?threadid=1785)


Geschrieben von eulerscheZahl am 07.02.2014 um 20:55:

 

B hat von A geerbt, das bezieht sich auf Variablen und Methoden, sofern sie public (Zugriff ist von überall aus möglich) oder protected (Zugriff durch eine Klasse und deren abgeleitete Klassen) ist. Auf Variablen/Methoden von A, die private sind, kann B nicht zugreifen.



Geschrieben von tigerbine am 07.02.2014 um 21:18:

 

Ok, danke Wink



Geschrieben von tigerbine am 08.02.2014 um 11:25:

 

Hallo, ich schon wieder.

Wir haben eine abstrakte Klasse mit einer abstracten Methode.
code:
1:
2:
3:
4:
5:
 public abstract class Drache {
  public abstract void spucken();
}

N

Nun eine davon abgeleitete Klasse, die dann die Methode spucken implementieren muss.

code:
1:
2:
3:
4:
5:
public class SchneckenDrache extends Drache {
  public void spucken() {
        //Spucke Schleim }
}

Nun möchte man einen Schneckendrachen erzeugen und ihn Schleim spucken lassen. Warum macht man das so:

code:
1:
2:
3:
4:
5:
6:
public static void main(String[] args){
  Drache drache = new Schneckendrache();
  drache.spucken();
}


Ich denke jetzt an das Trompeterbeispiel von Seite 3 Karlito (Leider darf ich noch keine Links posten). Da sagten wir, man kann in Drache nur benutzen, was in der Klasse Drache ist. Dort gibt es aber nur eine leere Methode spucken. Warum funktioniert das Schleimspucken dennoch? Und was ist der Unterschied zum Trompeter?

Hoffe ihr versteht mein Problem.

edit:
liegt es daran, dass die Methoden gleich heißen? Denn auf eine andersnamige Methode kann ich nicht zugreifen über die Deklaration Drache. Woher weiß java aber, dass es im Falle von spucken in der Objektreferenz schauen muss? Klappt auch bei nicht abstrakten Klassen und Methoden. Also woher weiß die Klasse drache, dass ihre Methode überschrieben wurde?



Geschrieben von Karlito am 08.02.2014 um 15:40:

 

Hallo tigerbine,

ein Drachen hat doch die Methode spucken. Ob sie implementiert ist oder nicht, ist nicht entscheidend. Eine Abstrakte Klasse ist eine Art Mischung zwischen Normalen Klassen und Interfaces... (Bei Interfaces sind keine Methoden implementiert, bei normalen Klassen sind alle Methoden implementiert und bei Abstrakten Klassen ist normalerweise ein Teil der Methoden implementiert und ein Teil nicht...).

Der Unterschied zum Trompeter ist, dass der Musiker ja die Methode mundstueckWechseln() nicht hat. Somit könnte man folgendes nicht machen:

code:
1:
2:
Musiker trompeter = new Trompeter();
trompeter.mundstueckWechseln(); //geht nicht, da Musiker die Methode nicht haben!


Entlang der Vererbungshierarchie kann das Verhalten von Methoden verändern, solange diese nicht dagegen geschützt sind. Du weißt ja bereits, dass alle Objekte von der Klasse Object erben, auch wenn man das nicht mit angibt. Somit haben alle Objekte auch zum Beispiel die Methode toString(). Oft ist es sinnvoll diese Methode zu überschreiben.

Beispiel:
code:
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
public class Trompeter extends Musiker{
	private string name;

	public Trompeter(string name){
		this.name = name;
	}

	public void mundstueckWechseln(){
		//WechsleMundstück
	}

	@Override //Kennzeichnung, dass man eine bereits existierende 
                  //Methode überschreibt
	public string toString(){
		return "Trompeter " + name;
	}
} 


Hier würde dann die Standardimplementierung von toString() überschrieben und das neue Verhalten wäre gültig. Probier am besten mal aus, was passiert, wenn du trompeter.toString() aufrufst bevor und nachdem du die Methode überschrieben hast.

VG,

Karlito



Geschrieben von ed209 am 08.02.2014 um 18:07:

 

Zitat:

liegt es daran, dass die Methoden gleich heißen? Denn auf eine andersnamige Methode kann ich nicht zugreifen über die Deklaration Drache.

Wenn die Methode gleich heisst und die gleichen Übegabeparameter hat dann ist es für Java die passende Methode.

Zitat:

Also woher weiß die Klasse drache, dass ihre Methode überschrieben wurde?

Jedes Object weiß zu welcher Klasse es gehört und welche Methoden was machen.
Der Compiler stellt sicher, daß alle deklarierten Methoden auch implementiert werden. Probier einfach mal aus, was passiert wenn Du die
"spucken" methode weglässt.
Generell empfehle ich Dir, einfach mal ein paar unterschiedliche Sachen auszuprobieren und zu gucken wie der Java-Compiler und die Java-Runtime reagieren.

Gruss,
ED



Geschrieben von tigerbine am 09.02.2014 um 13:50:

 

Zitat:
Original von Karlito
Hallo tigerbine,

ein Drachen hat doch die Methode spucken. Ob sie implementiert ist oder nicht, ist nicht entscheidend. Eine Abstrakte Klasse ist eine Art Mischung zwischen Normalen Klassen und Interfaces... (Bei Interfaces sind keine Methoden implementiert, bei normalen Klassen sind alle Methoden implementiert und bei Abstrakten Klassen ist normalerweise ein Teil der Methoden implementiert und ein Teil nicht...).


Also was mich eben wunder ist, dass wenn ich drache.spucken() aufrufe, warum er dann nicht einfach nichts tut, die Methode ist da ja nicht mit Anweisungen gefüllt. Was wäre, wenn ich dort "Ich spucke nicht" eintragen würde. spuckt der drache dann, oder nicht. Kann ich erst morgen testen.

Danke schon mal wieder für eure Hilfe, aber meine Fragen bleiben euch sicher in nächster Zeit noch erhalten.



Geschrieben von eulerscheZahl am 09.02.2014 um 19:32:

 

Meinst du so?
code:
1:
2:
3:
4:
5:
6:
public class SchneckenDrache extends Drache {
	public void spucken() {
	        System.out.println("Ich spucke nicht"); 
	}
}

Wenn du
Drache drache = new SchneckenDrache();
schreibst, ist drache vom Typ SchneckenDrache, weil der dazugehörige Konstruktor zum erzeugen verwendet wurde. Da ist dann auch klar, welche Funktion mit drache.spucken(); aufgerufen wird. Wenn du den Drachen spucken lässt, pinselt er dir "Ich spucke nicht" in die Konsole.

Zitat:
Leider darf ich noch keine Links posten

Das war leider nötig, da hier viele Spambots unterwegs waren - wir haben hier mehr Miglieder als Beiträge und etliche dieser Account wurden zum Spammen erstellt unglücklich
Wenn du ein paar Beiträge außerhalb des Off-Topic verfasst, sollte sich das bald ändern (die genaue Grenze, ab wann man Links einfügen darf, kenne ich nicht).



Geschrieben von tigerbine am 10.02.2014 um 16:58:

 

Ich meinte das so:
code:
1:
2:
3:
4:
5:
6:
public class Drache {
	public void spucken(){
		System.out.println("Ich spucke nicht.");
	};


code:
1:
2:
3:
4:
5:
6:
7:
8:
9:
public class SchneckenDrache extends Drache {
	public void spucken() {
		System.out.println("Ich spucke Schleim.");
	}
	public void rennen() {
		System.out.println("Ich renne schnell.");
	}


code:
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
public class Spiel {

	public static void main(String[] args) {
		
		Drache drache = new SchneckenDrache();
		drache.spucken();
		
	}


Nun kann ich über drache. nur die Methode "spucken" aufrufen. Die Methode "rennen" nicht. Das ging für mich konform zu den Aussagen von Karlito, weil ich die Deklaration über Drache und nicht SchneckenDrache gemacht habe. Drache besitzt keine Methode "rennen".

Nun kommt mein Problem. Warum wird dann nicht die Methode "spucken" von Drache ausgeführt? Warum kann man hier (und wird hier) eine Methode aus SchneckenDrache ausgeführt. Wieso "überwiegt" in diesem Fall der Konstruktor die Deklaration?

Die zwei Fälle passen für mich nicht zusammen. Sorry, aber die Leitung ist da wohl was länger. Augenzwinkern



Geschrieben von ed209 am 10.02.2014 um 21:16:

 

TL;DR: Du hast immer einen Konstruktor, und von dem hängt ab wie die Methoden implementiert sind.

Welche Implementierung einer Methode auf einem bestimmten Objekt aufgerufen wird, hängt bei Java immer von der Klasse ab zu der das Objekt gehört.
Die Klasse bestimmt sich immer durch den Konstruktor der aufgerufen wird.
code:
1:
Drache drache

bestimmt lediglich den Typen der Variable drache.

Der Typ der Variable gibt an, dass die Variable bestimmte Methoden hat (in diesem Fall ist der Typ Drache und hat damit eine Methode "spucken" ohne Parameter und Rückgabewert), während die Klasse bestimmt wie die Methoden implementiert sind (in diesem Fall ist ein Schneckendrache der Schleim spuckt).



Geschrieben von tigerbine am 11.02.2014 um 09:30:

 

Prima. Mit "WAS und WIE" kann ich mir das nun merken. Tanzen



Geschrieben von tigerbine am 13.02.2014 um 16:44:

  Sets

Eine/erste Frage zum Thema Mengen. Ich möchte alle geraden Zahlen zwischen 1 und 40 in die Menge A packen.

code:
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
package de.galileocomputing.schroedinger.java.kapitel08;

import java.util.HashSet;
import java.util.Set;


public class SetA {

	
	public static void main(String[] args) {
		
		Set<Integer> A = new HashSet<>();
		for (int i=2; i <= 40; i=i+2) {
			A.add(i);
			System.out.println(A);
		}
		
	}

}


Nun wundere ich mich über die Ausgabe. Bis 14 ist für mich noch alles im Lot. Was ist dann los?

code:
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
[2]
[2, 4]
[2, 4, 6]
[2, 4, 6, 8]
[2, 4, 6, 8, 10]
[2, 4, 6, 8, 10, 12]
[2, 4, 6, 8, 10, 12, 14]
[16, 2, 4, 6, 8, 10, 12, 14]
[16, 2, 18, 4, 6, 8, 10, 12, 14]
[16, 2, 18, 4, 20, 6, 8, 10, 12, 14]
[16, 2, 18, 4, 20, 6, 22, 8, 10, 12, 14]
[16, 2, 18, 4, 20, 6, 22, 8, 24, 10, 12, 14]
[16, 2, 18, 4, 20, 6, 22, 8, 24, 10, 26, 12, 14]
[16, 2, 18, 4, 20, 6, 22, 8, 24, 10, 26, 12, 28, 14]
[16, 2, 18, 4, 20, 6, 22, 8, 24, 10, 26, 12, 28, 14, 30]
[32, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30]
[34, 32, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30]
[34, 32, 2, 4, 36, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30]
[34, 32, 2, 38, 4, 36, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30]
[34, 32, 2, 38, 4, 36, 6, 8, 40, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30]


edit: mit einem TreeSet bekomme ich eiene geordnete Ausgabe. Dennoch verwirrt mich die Unordnung, da die Zahlen in der for Schleife ja der Größe nach an die Menge übergeben werden.



Geschrieben von eulerscheZahl am 13.02.2014 um 19:45:

 

Wenn du beim HashSet erst die 4 und dann die 2 einfügst, ist die 2 trotzdem vor der 4.

Da ich dein Vorwissen nicht kenne, hole ich etwas weiter aus:
Stell dir vor, du hast ein Wörterbuch und willst dann einen Eintrag hinzufügen. Logischerweise fügst du ihn dort ein, wo er nach alphabetischer Reihenfolge hingehört und nicht ans Ende. Genau das tut Java hier auch. Es sortiert den Eintrag ein, auch wenn die Sortierung etwas seltsam scheinen mag.
Du kannst aber nicht nur ein Set<Integer> erstellen, sondern auch String, Double oder sogar eingene Klassen verwenden. Hierfür gibt es Funktionen, die das alles zu einer Zahl mit z.B. 4 Byte umwandeln können (was zur Folge hat, dass etwa 2 Zeichenketten des selben Hash haben können, das heißt dann Kollision). Nach diesem Hashwert sortiert werden die Zahlen dann in die Liste eingefügt.

Der Vorteil ist, dass man die Liste mit logarithmischer Zeit durchsuchen kann: will man wissen, ob ein Wert in der Liste steht, bildet man den Hash. Ist der größer als der des ersten Eintrags und kleiner als der des letzten, vergleicht man danach mit dem Eintrag in der Mitte. Nun prüft man wieder, in welchem der beiden Intervalle ( ]Anfang;Mitte[ oder ]Mitte;Ende[ ) der Wert liegt, konnte als in nur einem Schritt die Möglichkeiten auf die Hälfte reduzieren.



Geschrieben von tigerbine am 13.02.2014 um 19:48:

 

Danke für die Erklärung!



Geschrieben von Karlito am 13.02.2014 um 21:45:

 

Hallo euler, hallo tigerbine,

noch ein paar Anmerkungen:
Hashsets sind so konstruiert, dass möglichst schnell Dopplungen gefunden werden können. Dazu wird, wie von euler beschrieben eine Hashfunktion benutzt.
Der Zugriff auf das Hashset funktioniert jedoch anders als von euler beschrieben und hat auch in vielen Fällen eine bessere Laufzeit (O(1)!).

Erklärung:
Man stelle sich ein Array mit 10 Plätzen vor. Nehmen wir nun eine Funktion, welche einem Objekt (hier einer Zahl) einen Hashwert zuordnet. Bei einem Array mit 10 Werten benutzt man einfach eine Hashfunktion, welche die Werte 0-9 ausgibt. Dabei entspricht der Hashwert genau dem Index im Array.

Bei einem Set ist diese Art der Speicherung sehr günstig, da jedes Objekt in einem Set (entsprechend der mathematischen Menge) nur ein mal Vorkommen darf und die Ordnung keine Rolle spielt.

Fügt man nun ein Objekt in dieses Set ein, so wird der Haswert gebildet und geschaut, ob sich an dem Ort im Array bereits ein Objekt befindet. Wenn ja, wird das Objekt mit dem einzufügenden Objekt verglichen. Sind sie gleich, so wird das einzufügende Objekt verworfen. Sind sie ungleich (Kollision), dann wird an der Stelle im Array ein weiteres Objekt eingehängt. Dafür wird im Normalfall eine verkettete Liste verwendet.

Edit: Befindet sich an der Stelle kein Objekt, so wird eine neue verkettete Liste mit einem Element angelegt in an die Stelle im Array gelegt.

Beim Auslesen des gesamten Hashsets werden nun alle Zellen darauf geprüft, ob sie einen Inhalt haben oder nicht. Wenn ja wird der Inhalt ausgegeben. (Eventuell gibt es geschicktere Implementierungen).

Edit: dabei hängt die Reihenfolge von der verwendeten Hashfunktion bzw. den verwendeten Hashfunktonen ab. (siehe weiter unten)

Will man untersuchen, ob ein Objekt bereits in der Liste ist, so bildet man wie im Einfügevorgang einen Hashwert schaut am ensprechenden Index danach, ob das Objekt sich da befindet. Meistens sollte dabei nur ein oder kein Objekt gefunden werden und somit ist der Zugrif O(1). Da Hashfunktionen aber nicht ideal sind, und die Eingabewerte auch nicht, kann es dazu kommen, dass viele Kollisionen entstehen. Somit müsste die gesamte verkettete Liste nach dem Objekt durchsucht werden und die Suche hätte lineare Laufzeit.

Weiteres: Hashsets haben eine Initalgröße (s. Doku) und vergrößern sich automatisch und zwar bereits bevor das verwendete Array voll ist um Kollissionen zu vermeiden. Dabei wird die benutzte Hashfunktion dynamisch angepasst und teilweise werden nach dem Vergrößern mehre Arrays mit den dazugehörigen Hashfunktionen genutzt. Weiterhin ist das Ziel einer guten Hashfunktion für Hashtabellen eine gute Streuung um Kollisionen zu vermeiden. O(1) wird wie beschrieben als ideal angesehen und in der Realität selten erreicht, aber im Allgemeinen nähert es sich konstanter Laufzeit.

@euler: was du beschrieben hast ist binäre Suche und wird bei sortierten Arrays angewendet.

VG,

Karlito



Geschrieben von eulerscheZahl am 14.02.2014 um 06:10:

 

Danke für die Korrektur, werde ich mir merken. Daumen hoch


Forensoftware: Burning Board, entwickelt von WoltLab GmbH