[Java] Im Klassen-Array Methoden untergeordneter Klassen aufrufen

Hier muss man aufpassen! Es wir kein neues Objekt erstellt, sondern die Objekt-Referenz aus dem Array (bei Java stecken in einem Array Referenzen zu Objekten, keine Objekte selbst) in einer lokalen Variablen gespeichert (auch Variablen sind demnach nie Objekte sondern nur Referenzen auf Objekte im Heap oder null). Dieses grundlegende Konzept MUSS man unter Java möglichst früh begreifen (erspart einem viele Probleme :D). Hierzu zum Einlesen: Mit Referenzen arbeiten, Identität und Gleichheit

Das beantwortet somit zum teil also auch diese Frage.

So hatte ich es gemeint nur schlecht erklärt.
 
Hier hat sich ja einiges getan :D

Das Tutorial, mit dem ich gerade arbeite ist das hier: https://www.youtube.com/watch?v=b1pDj1gx9zs
In dem letzten Video wurde instanceof eingeführt und er meinte, dass man damit eben auch die Methoden aufrüfen könne. Da er das aber nicht im Video gemacht hat, dacht ich mir ich probiere es mal selbst aus.

Das die Variablen natürlich einen besseren Namen bekommen sollten, ist mir bewusst, die Variable a war nur kurz als Test erstellt. Aber selbst da sollte man am Anfang nicht schlampig arbeiten... In Schleifen immer nur einen Buchstaben zu verwenden, hatten die sogar in Informatik I bei uns an der Uni gemacht, sollte ich mir wohl dann auch abgewöhnen.

Danke für den Link zu den Referenzen, jetzt ist das mit dem "erstellten" Objekt noch etwas klarer. Also im Endeffekt wird das Objekt hund erstellt, dass auf den Arrayspeicherplatz zeigt, versteh ich das richtig? Hat das Ähnlichkeiten mit den Pointern aus C++?

Generell danke für die ganzen Inputs, da macht das alles gleich nochmal mehr Spaß ;)

Edit: Das Buch Java ist eine Insel dient eher als Nachschlagewerk oder baut das schon Schrittweise aufeinander auf? Das wäre dann natürlich super zum weiterarbeiten dann
 
Zuletzt bearbeitet:
Die Insel ist schon mehr ein Nachschlagewerk als ein Guide für absolute Anfänger, aber es baut schon schrittweise aufeinander auf. Sobald man Grundprinzipien des Programmierens allgemein verstanden hat, kann man damit gut Java lernen.

Reine For-Schleifen würde ich übrigens als einzige Stelle gelten lassen, an denen einbuchstabige Variablennamen opportun sind. Aber meist benutzt man eh eine For-Each-Schleife, wenn der Index an sich nicht wichtig ist. Dort ist der Variablenname dann wiederum nicht egal.

Sekundieren muss ich hier auch nochmal: dein Thread ist Balsam im Vergleich zu anderen Threads. Hier will jemand lernen. Hier kommt jemand voran. Hier rafft jemand Sachen. Das gefällt mir! :)
 
Gismodin schrieb:
In dem letzten Video wurde instanceof eingeführt und er meinte, dass man damit eben auch die Methoden aufrüfen könne. Da er das aber nicht im Video gemacht hat, dacht ich mir ich probiere es mal selbst aus.
Das er es nicht explizit gezeigt hat macht aber deutlich, dass man das in der Praxis möglichst nicht so lösen sollte.:D

Die aus meiner Perspektive geläufigste Anwendung findet instanceof (wobei seit Multi-catch auch seltener) beim Exception Handling. Innerhalb eines try Blocks (weiß nicht ob du das schon alles kennst) können häufig verschiedene Exceptions ausgelöst werden die man mittels catch ( Exception e ) zunächst alle abfangen und im Anschluss differenziert behandeln kann. Hier siehst du was ich meine:
Zusammenfassen gleicher catch-Blöcke

Exception ist die Basisklasse und SQLException und IOException sind davon abgeleitet. Diese verraten also genauer was für ein Fehler aufgetreten ist und ermöglichen anders darauf zu reagieren.

Gismodin schrieb:
Also im Endeffekt wird das Objekt hund erstellt, dass auf den Arrayspeicherplatz zeigt, versteh ich das richtig? Hat das Ähnlichkeiten mit den Pointern aus C++?
Mit dem Operator "new" wird ein neues Objekt im Speicher (Heap space) erzeugt und die Referenz auf diesen Speicherort zurückgegeben. Im Array landet also nur die Referenz. Das Konzept der Referenzen ist vergleichbar mit Pointern in anderen Programmiersprachen. Nur dass diese in Java deutlich abstrakter sind.

PS: Ich habe "Java ist auch eine Insel" eigentlich immer mehr als Ergänzung und Nachschlagewerk genutzt. Vermute um das komplett schrittweise durchzugehen ists zu umfangreich und die Bespiele wenig zusammenhängend.
 
Zuletzt bearbeitet:
G00fY schrieb:
Die aus meiner Perspektive geläufigste Anwendung findet instanceof (wobei seit Multi-catch auch seltener) beim Exception Handling. Innerhalb eines try Blocks (weiß nicht ob du das schon alles kennst) können häufig verschiedene Exceptions ausgelöst werden die man mittels catch ( Exception e ) zunächst alle abfangen und im Anschluss differenziert behandeln kann. Hier siehst du was ich meine:
Zusammenfassen gleicher catch-Blöcke
Das nutzen von instanceof beim Exception Handling ist aber auch sehr schlechter Stil. Selbst das abfangen von der Klasse Exception halte ich persönlich schon für schlechten Stil.
Mit Java 7 wurde außerdem das Multi Catch eingeführt womit aus dem Beispiel von deinem Link

Code:
try
{
  irgendwas kann SQLException auslösen ...
  irgendwas kann IOException auslösen ...
  Point p = null;
  p.setX( 2 );      //  NullPointerException
}
catch ( Exception e )
{
  if ( ! ( e instanceof SQLException || e instanceof IOException ) )
    throw e;
  Behandlung
}

Das hier werden würde.

Code:
try
{
  irgendwas kann SQLException auslösen ...
  irgendwas kann IOException auslösen ...
  Point p = null;
  p.setX( 2 );      //  NullPointerException
}
catch ( SQLException | IOException e )
{
  Behandlung
}
 
Hatte mich schon gewundert, ich komme ja mehr aus der C# Ecke und da kamm Catch Blöcke verketten um verschieden Typen abzufangen. Es macht schon Sinn als letztes die Klasse Exception zu fangen, die Details irgendwo zu loggen und dann ggf. das Programm zu beenden, zumindest wenn es in dem Kontext nicht vorgesehen war.
 
Fonce schrieb:
Das nutzen von instanceof beim Exception Handling ist aber auch sehr schlechter Stil. Selbst das abfangen von der Klasse Exception halte ich persönlich schon für schlechten Stil.
Sagte ja nur, dass instanceof dort häufiger zum Einsatz kommt, nicht dass ich grundsätzlich empfehle das so zu lösen. Dennoch würde ich nicht von "sehr schlechtem Stil" sprechen. Es ist sinnvoller nur die geworfenen Exceptions anzufangen. Das geht im übrigen auch mit mehreren Catch Blöcken. Jedoch besteht dann die Gefahr, dass durch eine Unachtsamkeit zB NullPointerExceptions übersehen werden. Je nach Methode interessiert der Fehler im Detail vielleicht auch nicht. Beim Error Handling gibt's afaik gar nicht DEN Stil. Das hängt stark vom Anwendungsfall ab.
 
Firestorm- schrieb:
Ich befürchte, Du erkennst den Punkt nicht. Bei Code, der wie der oben gezeigte aussieht, ist das trivial. Wenn Du aber 3-fach geschachtelte Rekursionen hast, bringt dir Dein Syntax-Highlightning niente, nada, nothing! Und jetzt noch Variablennamen, die a, b, c, i, r, x und y heißen, dann bist Du bedient, promised!
Wenn dein Code unlesbar wird empfehle ich eine Umstrukturierung. Rekursive Teile in Methoden auslagern. Schon wird es übersichtlicher und ein i ist kein Problem :)
Ein Hilfsmittel wäre hier Sonar einzusetzen.


Aber um zumindest zum Thema etwas beizutragen.
Ich bevorzuge NullChecks statt NullPointerExceptions.
Fortgeschrittene können dann auch @Nonnull und @Nullable Annotationen verwenden um auf mögliche Probleme hingewiesen zu werden.
 
Catch-Blöcke wurden sogar ziemlich früh eingeführt, um die Fehlermeldung beim Teilen durch 0 abzufangen.

Multi-Catch bedeutet einfach, dass Catch nun mehrere Argumente behandeln kann?

Nachdem das Buch "Java ist auch eine Insel" bei uns an der Uni zum ausleihen war, hab ichs mir einfach mal geholt.
 
Gismodin schrieb:
Multi-Catch bedeutet einfach, dass Catch nun mehrere Argumente behandeln kann?
Genau. Wie Fonce gezeigt hat, wurde mit Java 7 Pipe (|) als Operator zum Auflisten von Exceptions im try-catch Block hinzugefügt.
 
Zuletzt bearbeitet:
Nachdem wir hier ja auch die catch-Blöcke schon gut thematisiert haben, stell ich die Frage dazu auch gleich noch hier.

Es soll ein Objekt der Klasse Mensch geklont werden, der wiederum als Attribut ein Objekt der Klasse Hund besitzt. Das klappt auch alles super. Mein Problem ist eher eine Logikfrage, hier der Code:
Code:
public static void main(String[] args) {
		Hund hund1 = new Hund("Bobby", "braun", 5);
		Mensch human1 = new Mensch("karl", "braun", 18, 90, hund1);		

		Mensch human3;
		try {
			human3 = human1.clone();
		} catch (CloneNotSupportedException e) {
			e.printStackTrace();
			System.out.println("Ein Fehler ist aufgetreten! Das Programm wird beendet");
			System.exit(0);
			human3 = null;
		}
		human1.hund.setAlter(7);
		System.out.println(human1.hund.getAlter());
		System.out.println(human3.hund.getAlter());
		System.out.println(human1.equals(human3));
	}

Das Programm lässt sich nur starten, wenn human3 in allen Fällen initilisiert wird, also entweder schon in Zeile 5 mit Mensch human3 = null; oder wie im Code gerade bei Zeile 12. Aber eigentlich ist das doch unnötig, da das Programm, sollte es nicht funktionieren zuvor beendet werden soll?
Liegt das daran, dass diese Standard-Exception sowieso eher nutzlos ist? Wenn die Klasse nicht als Cloneable deklariert ist, würde das Programm ja gar nicht erst starten, es würde also nie in den catch-Block kommen.
 
Ersetz mal System.exit(0); (sehr schlechter Stil übrigens) durch return;
 
Gismodin schrieb:
Catch-Blöcke wurden sogar ziemlich früh eingeführt, um die Fehlermeldung beim Teilen durch 0 abzufangen.

Bei solch Dingen bietet es sich besonders an auf Catch zu verzichten. Hier ist ein einfaches "if (variable == 0)" oder "if (variable != 0)" - je nachdem was mehr Sinn ergibt - sowohl performanter, logischer zu verstehen (wenn jemand anderes den Code liest, oder du selbst nach einer längeren Zeit) und schöner.

Meiner Meinung nach sollte man möglichst immer so programmieren, das Exceptions erst gar nicht auftreten können, anstatt Fehlerbehandlungen für diese einzubauen. Zumindest dann, wenn es um Exceptions geht, die von "außerhalb" (User-Input, IO, ...) geht.

Ich nutze Exceptions nur, um Programmierfehler (bspw. wenn ein Argument null ist, obwohl es das nicht sein darf) aufzuzeigen, oder wenn es ein nicht vorhersehbarer - meist externer - Fehler (wie z.B. Absturz einer Datenbank) ist.
 
Zuletzt bearbeitet:
Drexel schrieb:
Wie lautet denn die Fehlermeldung andernfalls?

Exception in thread "main" java.lang.Error: Unresolved compilation problems:
The local variable human3 may not have been initialized
The local variable human3 may not have been initialized

at main.Equals.main(Equals.java:29) (entspricht Zeile 16 oben)

Das kann ja sein, dass es ein schlechter Stil ist, dennoch soll bei dieser Übung das Programm dort beendet werden, mit return wird ja nur der catch-Block abgeschlossen und die Befehle danach trotzdem ausgeführt.

@Bagbag: Das habe ich auch gemacht ;) Ich wollte nur sagen, mit welchem Beispiel catch eingeführt wurde. Ein Rechenprogramm bietet sich ja meist am Anfang an und da kann der Nutzer ja schnell mal diese Fehlermeldung hervorrufen.

Die clone-Methode benötigt aber den catch-Block ohne den sagt er sofort, dass diese Fehlerbehandlung fehlt.
 
Gismodin schrieb:
Das kann ja sein, dass es ein schlechter Stil ist, dennoch soll bei dieser Übung das Programm dort beendet werden, mit return wird ja nur der catch-Block abgeschlossen und die Befehle danach trotzdem ausgeführt.
Das ist so nicht richtig. Ein return-Statement beendet die Methode, nicht einen (try-catch) Block. Es wird hier höchstens noch ein finally-Block ausgeführt (wenn einer vorhanden wäre) und das wäre dann auch so vom Programmierer gewollt. Mit der Holzhammer-Methode System.exit() wäre das nicht der Fall.

Da es sich um die main-Methode handelt, wird das Programm also mit return beendet.
 
Hab das eben mal mit einem kurzen Divisionsprogramm ausprobiert
Code:
public static void main(String[] args) {
		int zahl1, zahl2;
		Scanner s = new Scanner(System.in);
		
		System.out.println("2 Zahlen eingeben:");
		zahl1 = s.nextInt();
		zahl2 = s.nextInt();
		
		int ergebnis = 0;
		
		try {
			ergebnis = zahl1 / zahl2;
		} catch (ArithmeticException e) {
			return;
		}
		System.out.println(ergebnis);
		System.out.println("Test");
	}

Zeigt sich, dass du natürlich recht hast. Allerdings kann ich hier auch problemlos das return durch System.exit(0) ersetzen, um auf das gleiche Ergebnis zu kommen.

Trotzdem verstehe ich nicht, warum ich im Falle des Abbruchs, human3 initialisieren müsste. Hier nochmal die Fehlermeldung, wenn eben nicht initialisiert:

Exception in thread "main" java.lang.Error: Unresolved compilation problems:
The local variable human3 may not have been initialized
The local variable human3 may not have been initialized

at main.Equals.main(Equals.java:29) (entspricht Zeile 16 oben)
 
Also eine Regel die du dir merken solltest ist keine uninitialisierten Objekte zu haben. Am besten natürlich direkt mit dem eigentlichen Wert oder im Falle von human3 zumindest mit null.
 
Gismodin schrieb:
Trotzdem verstehe ich nicht, warum ich im Falle des Abbruchs, human3 initialisieren müsste.
Das ist der Unterschied zw. Syntax und Semantik. Du verstehst System.exit() als Programmende (Semantik), der Compiler sieht darin nur einen normalen Funktionsaufruf (Syntax). Nur bei return ist Syntax und Semantik identisch.

Uninitialisierte Variablen halte ich nicht für ein Problem, schließlich warnt der Compiler bzw. die IDE, wenn solche Fälle eintreten.
 
Gismodin schrieb:
Das kann ja sein, dass es ein schlechter Stil ist, dennoch soll bei dieser Übung das Programm dort beendet werden, mit return wird ja nur der catch-Block abgeschlossen und die Befehle danach trotzdem ausgeführt.

Ist das so? Sollte Return nicht die Methode beenden?
 
Zurück
Oben