Martin Jung: nun: JAVA

Beitrag lesen

Hi Daniela,

Hat er das jemals behauptet?

Nicht explizit. Ich ging aber, offensichtlich irrtümlicherweise, davon aus.
Weißt Du, Argumentationen im Stile von "ich finde etwas blöd, weil BEHAUPTUNG1, BEHAUPTUNG2, BEHAUPTUNG 3. Ich möchte aber darüber nicht näher sprechen, weil ich keine (!!) Diskussion vom Zaun brechen will" halte ich, gelinde gesagt, für eigenartig.

Genereller Grund: Dank einem einzelnen! Javaw Prozess war meine Maschine
derart langsam das ich nicht mehr tippen konnte, auf dem Prozess lief
eine Servlets/JSP Anwendung mit einem einzelnen User, die Anwendung
bestand aus 1 Servlet + ungefähr 10 JSP und einzelne Action Klassen.

Hälst Du das für ein _generelles_ Argument für die Langsamkeit? Vielleicht lag es nur an der ungünstigen Parametrisierung der VM. Auf meiner Maschine (PII/350, 192 MB) habe ich keine Probleme, wenn z.B. TOMCAT, mySQL und KAWA gleichzeitig läuft (natürlich nicht mit 1000-en Usern ;-)) ).

Die ganzen Unzulänglichkeiten? ZB: bei welchen zu Java gehörenden Klassen
kann man clone benutzen

bei allen, die das Interface "Cloneable" implementieren.

, wann ist es Müll

Was? Die Methode clone()? Wenn sie falsch verwendet wird (Stichworte: flaches/shallow oder tiefes/deep Kopieren). Wie man die clone()-Methode implementiert ist Sache des Entwicklers und nicht der Sprache.

, oder das selbe mit equals das
auf die Referenz und nicht auf den Inhalt vergleicht?

Ich finde diese Thematik eigentlich einleuchtend.
Default-Verhalten:
1. Der "=="-Operator prüft bei allen _primitiven_ Datentypen _immer nur_ auf Wertgleichheit und bei _nicht-primitiven_ _immer nur_ auf Objektgleichheit der Referenz (andere sagen "auf Identität").

2. Zusätzlich gibt es eine Default-Implementation der Methoden equals() und hashCode() in "Object" (die somit in jedem abgeleiteten Objekt verfügbar sind). equals(Object obj) ist dabei simple implementiert: return (this == obj), sodass diese Methode auch auf Objektgleichheit prüft. D.h. standardmäßig führt die Verwendung von "==" und equals() bei Referenzen somit zum selben Ergebnis.

3. Da JAVA schlecht wissen kann, wann Objekte _inhaltlich_ bzw. in der Anwendungslogik gleich sind, ist es die Sache des Entwicklers, diese Bedingung durch Überschreiben von equals() entsprechend zu implementieren (er sollte natürlich auch tunlichst dafür sorgen, dass hashCode() dann ebenso entsprechend angepasst wird). Z.B. könnten zwei Bücher in der Anwendungslogik "gleich" sein, wenn sie denselben Titel und Autor haben, oder bereits, wenn sie nur denselben Titel haben. Bei zwei "inhaltlich gleichen" Buchobjekten würde eine entsprechende equals()-Methode dann "true" zurückgeben, "==" aber weiterhin zu "false" ausgewertet werden.
Beispiel: Bei String-Objekten (s.u.) ist die equals()-Methode derart überschrieben, dass auf inhaltliche Gleichheit geprüft wird -> "Hallo".equals("Hallo") == true.

Soweit finde ich das Konzept eigentlich leicht verständlich (obschon das zugrundeliegende Prinzip natürlich schwieriger zu verstehen ist als der Gebrauch einer for-Schleife). Bis auf _eine_ Ausnahme (s.u.) finde ich es auch sehr praktikabel, da immer vorhersehbar ist, was ein "=="-Vergleich prüft. Soweit ich weiß, gibt es in den C-Derivaten (oder nur C++) auch das Konzept der Operator-Überlagerung. Dies mag einerseits größere Flexibilität mit gut lesbarer Syntax verknüpfen, dürfte aber in der Praxis auch zu Problemen führen bzw. prinzipiell den Keim zur Verwirrung in sich tragen (Stichpunkt: Erben von Klassen, zu denen der Quellcode und/oder eine entsprechende Doku fehlt).

Strings: Hierbei gibt es in der Praxis in der Tat einige Missverständnisse (die aber eigentlich keine sind, da obige Regeln einfach nur angewandt werden).
Alle Strings sind ja bekanntlich in Java ebenfalls Objekte. JAVA unterscheidet aber zwischen Strings, die zur Compile-Zeit durch Variablenzuweisung angelegt werden, und solchen, die zur Laufzeit mittels "new String()" generiert werden. Der Hintergedanke war/ist die Vermeidung/Minimierung von Datenredundanz, also Resourcenschonung (ich erahne schon die spöttischen Kommentare ..). Zu diesem Zweck vewaltet die VM einen internen Pool von String-Objekten, der aus Compile-Zeit Strings beim Laden der Klassen gebildet wird (aber auch zur Laufzeit erweitert werden kann -> intern()-Methode von String).

Beispiel:
Du definierst 100 verschiedene String-Variablen, die aber alle denselben Inhalt zugwiesen bekommen ("Hallo").
Beim Laden der Klasse wird aus der Character-Folge der ersten String-Variablen ein entsprechendes String-Objekt erzeugt, diesem Pool hinzugefügt (mittels Aufruf der intern()-Methode von String durch die VM) und die Referenz auf dieses Objekt dann der Variablen zugewiesen.
Bei jeder weiteren Variablen wird zunächst geprüft (mittels Aufruf der equals()-Methode von String durch die VM), ob ein String-Objekt gleichen Inhalts im Pool bereits vorhanden ist. Ist dies nicht der Fall, wird wieder ein neues String-Objekt erzeugt, dem Pool hinzugefügt und die zurückgegebene Referenz der Variablen zugewiesen. Wenn aber bereits ein String-Objekt gleichen Inhalts existiert, wird eben diese Referenz zuückgegeben, sodass die zweite Variable dann dasselbe String-Objekt wie die erste referenziert. Alle 98 weiteren des Beispiels würden das ebenso tun. In diesem Falle würde der "=="-Vergleich für jede der 100 Variablen untereinander völlig korrekt "true" ergeben. Dies aber nur wegen Objektgleichheit, die in diesem Falle "zufälligerweise" auf der inhaltlichen Gleichheit zur Compile-Zeit beruht..
String-Objekte, die zur Laufzeit mittels "new String()" und demselben Inhalt generiert werden, stellen aber unterschiedliche Objekte dar. Daher ergäbe hierbei "==" eben "false".
Da dieses Verhalten in der Tat meistens für Verwirrung sorgt, ist man immer auf der richtigen Seite, wenn man inhaltliche Vergleiche ausschließlich durch Verwendung von equals() vornimmt.

Wir würdest Du denn das prinzipielle Problem des Unterschiedes zwischen Objekt- und Inhaltsgleichheit und deren Prüfung lösen (bzw. wie ist es denn in anderen OO-Sprachen gelöst? Eleganter? Einfacher?)

Nein, es nimmt ihm das Nachdenken ab indem es vorgaukelt dass es das nicht wäre,
das sind dann die schlecht designten Applikationen von denen du sprichst. Schliesslich
schreit Java dem Anwender ja entgegen, bei mir gibt es nichts gefährliches...

Meinst Du mit "gefährliches" Stolperfallen? Hat nicht jede Sprache ein Reservoir an solchen?
Mir hat Java nichts entgegengeschrien und auch nichts vorgegaukelt. Ich versuche zu verstehen, was einer Sprache mir bietet, welche Dinge problematisch sind, und verwende sie entsprechend.

Und Sun kann darüber entscheiden ganz alleine, ja, nette Community, aber keine
Druckmöglichkeit. BTW: es passiert wohl mir nichts dir nichts, wenn zb Bugmeldungen
als solved geschlossen werden, allerdings mit einer API-Änderung in der nächsten
Version (Beispiel erneut URLEncoder)

OK, in diesen Prozessen stecke ich zu wenig drin. Soweit mir bekannt ist, hat das W3C auch keinerlei Druckmöglichkeit auf die Umsetzung der Standards in Applikationen. Welche Organisationsform oder Intstitution böte denn Deiner Meinung nach solche Möglichkeiten? Wie ist das bei anderen Sprachen? Es ist doch letztlich immer vom Good-Will der beteiligten Entscheidungsträger abhängig, oder?
Ich lasse mich aber gerne eines Besseren belehren.

Er plädiert dafür, ältere Applikation nicht nur deswegen ändern zu müssen,
weil irgend ein Hersteller lust hat, alte APIs nicht mehr zu unterstützen.

Wieso muss er das? Die "alte" Laufzeit-Umgebung existiert doch weiterhin? Und da jede Applikation per default sowieso in ihrer eigenen VM läuft (und auch sollte), sehe ich da auch überhaupt kein Problem.

Und ganz genau das heist deprecated, Vorsicht, ändere es, irgendwann
unterstützen wirs einfach nicht mehr.

Für mich ist ein API ein Standard, und ein solcher wird weiterentwickelt wie viele andere auch. Dies bedeutet aber auch, dass man Fehlerhaftes korrigiert und Ungeeignetes/Gefährliches entfernt.
Wie stehst Du denn zu deprecated-Deklarationen verschiedener HTML-Tags durch das W3C?

War das jemals als Gegenargument gedacht und nicht viel eher als
was ist daran _so_ speziell.

OK, habe ich dann falsch interpretiert.

Die Sprache Java ist sehr schwach,

Das ist mir zu banal. Was meinst Du mit "schwach"?

die Klassenbibliothek Java
ist stärker, gehört jedoch nicht zu einer Sprache, und Java lässt
sowohl in der Klassenbibliothek, als auch in der Sprache sehr
elementare Dinge vermissen, so zum Beispiel für eine Sprache
sie sich wunderbar Objektorientiert nennt Design by Contract.

Kannst Du das Prinzip kurz erläutern? Von welchen OO-Sprachen wird das untertützt?
Was sind weitere Beispiele, die die Verwendung des Plurals "elementare Dinge" rechtfertigen?

Java ist kein sauberes OO,

Nun ja, ich sehe das weniger puristisch oder akademisch. Ich halte es für gut praktizierbares OO.

und es ist auch bei ernsthaftem und dauerhaftem Beschäftigen
nicht angenehmer mit Java zu arbeiten.

Das kann ich für Dich leider nicht widerlegen.

Speicherlöcher krieg ich dir in Java auch ohne Pointer hin.

Was meinst Du mit "Speicherloch"?

Und Designfehler in anderen Klassen machen diesen Vorteil zumindest für Servlets bis und mit
Java 1.3.1 zunichte -> URLEncoder (mein persönlicher Liebling)

Mit diesem Encoder sollte ich mich mal beschäftigen. Was ist eigentlich Euer konkretes Problem damit?

  • Java ist Binärcode-kompatibel
    Was soll das sein?

Verklausuliert für plattformunabhängig ;-))

Viele Grüße,
Martin